summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am37
-rw-r--r--lib/Makefile.in647
-rw-r--r--lib/config.h.in58
-rw-r--r--lib/debug.h114
-rw-r--r--lib/internal.h187
-rw-r--r--lib/libwimax.so.in3
-rw-r--r--lib/mc_rx.c535
-rw-r--r--lib/op-msg.c565
-rw-r--r--lib/op-open.c548
-rw-r--r--lib/op-reset.c122
-rw-r--r--lib/op-rfkill.c129
-rw-r--r--lib/pipe.c196
-rw-r--r--lib/re-state-change.c317
-rw-r--r--lib/wimax.c443
14 files changed, 3901 insertions, 0 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..2b9d879
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,37 @@
+
+INCLUDES = \
+ -I$(top_builddir)/include -I$(top_srcdir)/include \
+ $(LIBNL1_CFLAGS) \
+ $(I2400M_INCLUDES)
+
+noinst_HEADERS = debug.h internal.h
+
+lib_LTLIBRARIES = libwimaxll.la
+lib_LIBRARIES = libwimaxll.a
+libwimaxll_sources = \
+ op-open.c \
+ op-msg.c \
+ op-reset.c \
+ op-rfkill.c \
+ mc_rx.c \
+ pipe.c \
+ re-state-change.c \
+ wimax.c
+
+libwimaxll_la_SOURCES = $(libwimaxll_sources)
+# Trick automake
+libwimaxll_la_CFLAGS = $(AM_CFLAGS)
+# -version-info is CURRENT:REVISION:AGE
+# REVISION: inc for changes that do not affect the external interface
+# CURRENT: inc for added interfaces
+# AGE: inc for removed/changed existing interfaces
+libwimaxll_la_LDFLAGS = -version-info 0:0:0 $(LIBNL1_LIBS)
+libwimaxll_a_SOURCES = $(libwimaxll_sources)
+
+# Workaround renaming of libwimax to libwimaxll
+#
+# Dirty, but works the best -- will be removed soon
+install-exec-local:
+ $(mkdir_p) $(DESTDIR)/$(libdir)
+ (cd $(DESTDIR)/$(libdir) && ln -sf libwimaxll.so.0 libwimax.so.0)
+ (cd $(DESTDIR)/$(libdir) && ln -sf libwimaxll.so libwimax.so)
diff --git a/lib/Makefile.in b/lib/Makefile.in
new file mode 100644
index 0000000..e6328f0
--- /dev/null
+++ b/lib/Makefile.in
@@ -0,0 +1,647 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = lib
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/config.h.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libdir)"
+libLIBRARIES_INSTALL = $(INSTALL_DATA)
+LIBRARIES = $(lib_LIBRARIES)
+ARFLAGS = cru
+libwimaxll_a_AR = $(AR) $(ARFLAGS)
+libwimaxll_a_LIBADD =
+am__objects_1 = op-open.$(OBJEXT) op-msg.$(OBJEXT) op-reset.$(OBJEXT) \
+ op-rfkill.$(OBJEXT) mc_rx.$(OBJEXT) pipe.$(OBJEXT) \
+ re-state-change.$(OBJEXT) wimax.$(OBJEXT)
+am_libwimaxll_a_OBJECTS = $(am__objects_1)
+libwimaxll_a_OBJECTS = $(am_libwimaxll_a_OBJECTS)
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libwimaxll_la_LIBADD =
+am__objects_2 = libwimaxll_la-op-open.lo libwimaxll_la-op-msg.lo \
+ libwimaxll_la-op-reset.lo libwimaxll_la-op-rfkill.lo \
+ libwimaxll_la-mc_rx.lo libwimaxll_la-pipe.lo \
+ libwimaxll_la-re-state-change.lo libwimaxll_la-wimax.lo
+am_libwimaxll_la_OBJECTS = $(am__objects_2)
+libwimaxll_la_OBJECTS = $(am_libwimaxll_la_OBJECTS)
+libwimaxll_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libwimaxll_la_CFLAGS) \
+ $(CFLAGS) $(libwimaxll_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libwimaxll_a_SOURCES) $(libwimaxll_la_SOURCES)
+DIST_SOURCES = $(libwimaxll_a_SOURCES) $(libwimaxll_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+I2400M_INCLUDES = @I2400M_INCLUDES@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NMEDIT = @NMEDIT@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = \
+ -I$(top_builddir)/include -I$(top_srcdir)/include \
+ $(LIBNL1_CFLAGS) \
+ $(I2400M_INCLUDES)
+
+noinst_HEADERS = debug.h internal.h
+lib_LTLIBRARIES = libwimaxll.la
+lib_LIBRARIES = libwimaxll.a
+libwimaxll_sources = \
+ op-open.c \
+ op-msg.c \
+ op-reset.c \
+ op-rfkill.c \
+ mc_rx.c \
+ pipe.c \
+ re-state-change.c \
+ wimax.c
+
+libwimaxll_la_SOURCES = $(libwimaxll_sources)
+# Trick automake
+libwimaxll_la_CFLAGS = $(AM_CFLAGS)
+# -version-info is CURRENT:REVISION:AGE
+# REVISION: inc for changes that do not affect the external interface
+# CURRENT: inc for added interfaces
+# AGE: inc for removed/changed existing interfaces
+libwimaxll_la_LDFLAGS = -version-info 0:0:0 $(LIBNL1_LIBS)
+libwimaxll_a_SOURCES = $(libwimaxll_sources)
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign lib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+config.h: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status lib/config.h
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+install-libLIBRARIES: $(lib_LIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(libLIBRARIES_INSTALL) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+ $(libLIBRARIES_INSTALL) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ else :; fi; \
+ done
+ @$(POST_INSTALL)
+ @list='$(lib_LIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ p=$(am__strip_dir) \
+ echo " $(RANLIB) '$(DESTDIR)$(libdir)/$$p'"; \
+ $(RANLIB) "$(DESTDIR)$(libdir)/$$p"; \
+ else :; fi; \
+ done
+
+uninstall-libLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+ rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ done
+
+clean-libLIBRARIES:
+ -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES)
+libwimaxll.a: $(libwimaxll_a_OBJECTS) $(libwimaxll_a_DEPENDENCIES)
+ -rm -f libwimaxll.a
+ $(libwimaxll_a_AR) libwimaxll.a $(libwimaxll_a_OBJECTS) $(libwimaxll_a_LIBADD)
+ $(RANLIB) libwimaxll.a
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libwimaxll.la: $(libwimaxll_la_OBJECTS) $(libwimaxll_la_DEPENDENCIES)
+ $(libwimaxll_la_LINK) -rpath $(libdir) $(libwimaxll_la_OBJECTS) $(libwimaxll_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimaxll_la-mc_rx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimaxll_la-op-msg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimaxll_la-op-open.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimaxll_la-op-reset.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimaxll_la-op-rfkill.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimaxll_la-pipe.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimaxll_la-re-state-change.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimaxll_la-wimax.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mc_rx.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/op-msg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/op-open.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/op-reset.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/op-rfkill.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pipe.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/re-state-change.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wimax.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+libwimaxll_la-op-open.lo: op-open.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -MT libwimaxll_la-op-open.lo -MD -MP -MF $(DEPDIR)/libwimaxll_la-op-open.Tpo -c -o libwimaxll_la-op-open.lo `test -f 'op-open.c' || echo '$(srcdir)/'`op-open.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libwimaxll_la-op-open.Tpo $(DEPDIR)/libwimaxll_la-op-open.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='op-open.c' object='libwimaxll_la-op-open.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -c -o libwimaxll_la-op-open.lo `test -f 'op-open.c' || echo '$(srcdir)/'`op-open.c
+
+libwimaxll_la-op-msg.lo: op-msg.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -MT libwimaxll_la-op-msg.lo -MD -MP -MF $(DEPDIR)/libwimaxll_la-op-msg.Tpo -c -o libwimaxll_la-op-msg.lo `test -f 'op-msg.c' || echo '$(srcdir)/'`op-msg.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libwimaxll_la-op-msg.Tpo $(DEPDIR)/libwimaxll_la-op-msg.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='op-msg.c' object='libwimaxll_la-op-msg.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -c -o libwimaxll_la-op-msg.lo `test -f 'op-msg.c' || echo '$(srcdir)/'`op-msg.c
+
+libwimaxll_la-op-reset.lo: op-reset.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -MT libwimaxll_la-op-reset.lo -MD -MP -MF $(DEPDIR)/libwimaxll_la-op-reset.Tpo -c -o libwimaxll_la-op-reset.lo `test -f 'op-reset.c' || echo '$(srcdir)/'`op-reset.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libwimaxll_la-op-reset.Tpo $(DEPDIR)/libwimaxll_la-op-reset.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='op-reset.c' object='libwimaxll_la-op-reset.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -c -o libwimaxll_la-op-reset.lo `test -f 'op-reset.c' || echo '$(srcdir)/'`op-reset.c
+
+libwimaxll_la-op-rfkill.lo: op-rfkill.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -MT libwimaxll_la-op-rfkill.lo -MD -MP -MF $(DEPDIR)/libwimaxll_la-op-rfkill.Tpo -c -o libwimaxll_la-op-rfkill.lo `test -f 'op-rfkill.c' || echo '$(srcdir)/'`op-rfkill.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libwimaxll_la-op-rfkill.Tpo $(DEPDIR)/libwimaxll_la-op-rfkill.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='op-rfkill.c' object='libwimaxll_la-op-rfkill.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -c -o libwimaxll_la-op-rfkill.lo `test -f 'op-rfkill.c' || echo '$(srcdir)/'`op-rfkill.c
+
+libwimaxll_la-mc_rx.lo: mc_rx.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -MT libwimaxll_la-mc_rx.lo -MD -MP -MF $(DEPDIR)/libwimaxll_la-mc_rx.Tpo -c -o libwimaxll_la-mc_rx.lo `test -f 'mc_rx.c' || echo '$(srcdir)/'`mc_rx.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libwimaxll_la-mc_rx.Tpo $(DEPDIR)/libwimaxll_la-mc_rx.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mc_rx.c' object='libwimaxll_la-mc_rx.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -c -o libwimaxll_la-mc_rx.lo `test -f 'mc_rx.c' || echo '$(srcdir)/'`mc_rx.c
+
+libwimaxll_la-pipe.lo: pipe.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -MT libwimaxll_la-pipe.lo -MD -MP -MF $(DEPDIR)/libwimaxll_la-pipe.Tpo -c -o libwimaxll_la-pipe.lo `test -f 'pipe.c' || echo '$(srcdir)/'`pipe.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libwimaxll_la-pipe.Tpo $(DEPDIR)/libwimaxll_la-pipe.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pipe.c' object='libwimaxll_la-pipe.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -c -o libwimaxll_la-pipe.lo `test -f 'pipe.c' || echo '$(srcdir)/'`pipe.c
+
+libwimaxll_la-re-state-change.lo: re-state-change.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -MT libwimaxll_la-re-state-change.lo -MD -MP -MF $(DEPDIR)/libwimaxll_la-re-state-change.Tpo -c -o libwimaxll_la-re-state-change.lo `test -f 're-state-change.c' || echo '$(srcdir)/'`re-state-change.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libwimaxll_la-re-state-change.Tpo $(DEPDIR)/libwimaxll_la-re-state-change.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='re-state-change.c' object='libwimaxll_la-re-state-change.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -c -o libwimaxll_la-re-state-change.lo `test -f 're-state-change.c' || echo '$(srcdir)/'`re-state-change.c
+
+libwimaxll_la-wimax.lo: wimax.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -MT libwimaxll_la-wimax.lo -MD -MP -MF $(DEPDIR)/libwimaxll_la-wimax.Tpo -c -o libwimaxll_la-wimax.lo `test -f 'wimax.c' || echo '$(srcdir)/'`wimax.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libwimaxll_la-wimax.Tpo $(DEPDIR)/libwimaxll_la-wimax.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='wimax.c' object='libwimaxll_la-wimax.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwimaxll_la_CFLAGS) $(CFLAGS) -c -o libwimaxll_la-wimax.lo `test -f 'wimax.c' || echo '$(srcdir)/'`wimax.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) $(HEADERS) config.h
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLIBRARIES clean-libLTLIBRARIES \
+ clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-exec-local install-libLIBRARIES \
+ install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLIBRARIES uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLIBRARIES clean-libLTLIBRARIES clean-libtool ctags \
+ distclean distclean-compile distclean-generic distclean-hdr \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-exec-local install-html \
+ install-html-am install-info install-info-am \
+ install-libLIBRARIES install-libLTLIBRARIES install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-libLIBRARIES uninstall-libLTLIBRARIES
+
+
+# Workaround renaming of libwimax to libwimaxll
+#
+# Dirty, but works the best -- will be removed soon
+install-exec-local:
+ $(mkdir_p) $(DESTDIR)/$(libdir)
+ (cd $(DESTDIR)/$(libdir) && ln -sf libwimaxll.so.0 libwimax.so.0)
+ (cd $(DESTDIR)/$(libdir) && ln -sf libwimaxll.so libwimax.so)
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/config.h.in b/lib/config.h.in
new file mode 100644
index 0000000..b324b59
--- /dev/null
+++ b/lib/config.h.in
@@ -0,0 +1,58 @@
+/* lib/config.h.in. Generated from configure.in by autoheader. */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have <linux/wimax.h>. */
+#undef HAVE_WIMAX_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
diff --git a/lib/debug.h b/lib/debug.h
new file mode 100644
index 0000000..5d9fed7
--- /dev/null
+++ b/lib/debug.h
@@ -0,0 +1,114 @@
+/*
+ * Linux WiMax
+ * User Space API Debug Support
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * Simple debug printing macros
+ *
+ * FIXME: doc
+ * Invoke like:
+ *
+ * #define D_LOCAL 4
+ * #include "debug.h"
+ *
+ * At the end of your include files.
+ */
+#include <wimaxll.h>
+
+/* Master debug switch; !0 enables, 0 disables */
+#define D_MASTER (!0)
+
+/* Local (per-file) debug switch; #define before #including */
+#ifndef D_LOCAL
+#define D_LOCAL 0
+#endif
+
+#undef __d_printf
+#undef d_fnstart
+#undef d_fnend
+#undef d_printf
+#undef d_dump
+
+static inline
+void __d_dev_head(char *head, size_t size, const struct wimaxll_handle *_dev)
+{
+ if (_dev == NULL)
+ snprintf(head, size, "libwimax: ");
+ else if ((unsigned long)_dev < 4096) {
+ fprintf(stderr, "libwimax: E: Corrupt "
+ "device handle %p\n", _dev);
+ snprintf(head, size, "libwimax[dev_n/a]: ");
+ } else
+ snprintf(head, size,
+ "libwimax[%s]: ", _dev->name);
+}
+
+
+#define __d_printf(l, _tag, _dev, f, a...) \
+do { \
+ const struct wimaxll_handle *__dev = (_dev); \
+ if (D_MASTER && D_LOCAL >= (l)) { \
+ char __head[64] = ""; \
+ __d_dev_head(__head, sizeof(__head), __dev); \
+ fprintf(stderr, "%s%s" _tag ": " f, __head, \
+ __func__, ## a); \
+ } \
+} while (0 && _dev)
+
+#define d_fnstart(l, _dev, f, a...) __d_printf(l, " FNSTART", _dev, f, ## a)
+#define d_fnend(l, _dev, f, a...) __d_printf(l, " FNEND", _dev, f, ## a)
+#define d_printf(l, _dev, f, a...) __d_printf(l, "", _dev, f, ## a)
+#define d_test(l) (D_MASTER && D_LOCAL >= (l))
+
+static inline
+void __d_dump(const struct wimaxll_handle *dev,
+ const void *_ptr, size_t size)
+{
+ const unsigned char *ptr = _ptr;
+ char str[64];
+ size_t cnt, itr;
+ for (itr = cnt = 0; cnt < size; cnt++) {
+ itr += snprintf(str + itr, sizeof(str) - itr,
+ "%02x ", ptr[cnt]);
+ if ((cnt > 0 && (cnt + 1) % 8 == 0) || (cnt == size - 1)) {
+ __d_printf(D_LOCAL, "", dev, "%s\n", str);
+ itr = 0;
+ }
+ }
+}
+
+#define d_dump(l, dev, ptr, size) \
+do { \
+ if (d_test(l)) \
+ __d_dump(dev, ptr, size); \
+} while (0)
diff --git a/lib/internal.h b/lib/internal.h
new file mode 100644
index 0000000..57dbd32
--- /dev/null
+++ b/lib/internal.h
@@ -0,0 +1,187 @@
+/*
+ * Linux WiMax
+ * Internal API and declarations
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ */
+#ifndef __lib_internal_h__
+#define __lib_internal_h__
+
+enum {
+#define __WIMAXLL_IFNAME_LEN 32
+ /**
+ * WIMAXLL_IFNAME_LEN - Maximum size of a wimax interface
+ * name.
+ */
+ WIMAXLL_IFNAME_LEN = __WIMAXLL_IFNAME_LEN,
+ /**
+ * WMAX_MC_MAX - Maximum number of multicast groups that a
+ * WiMAX interface can offer (this doesn't count the
+ * reports group, which is separate).
+ */
+ WIMAXLL_MC_MAX = 5,
+};
+
+
+struct wimaxll_mc_handle;
+
+
+/**
+ * A description of a generic netlink multicast group
+ *
+ * \param name Name of the group
+ * \param id ID of the group
+ */
+struct wimaxll_mc_group {
+ char name[GENL_NAMSIZ];
+ int id;
+ struct wimaxll_mc_handle *mch;
+};
+
+
+/**
+ * A WiMax control pipe handle
+ *
+ * This type is opaque to the user
+ *
+ * \internal
+ *
+ * In order to simplify multithread support, we use to different \a
+ * libnl handles, one for sending to the kernel, one (for each pipe
+ * open to a multicast group) for reading from the kernel. This allows
+ * us to parallelize \c wimaxll_msg_write() and \c wimaxll_msg_read() at
+ * the same time in a multithreaded environment.
+ *
+ * FIXME: this needs some rewriting
+ *
+ * \param nlh_tx handle for writing to the kernel.
+ * Internal note: You \b have \b to set the handlers for
+ * %NL_CB_VALID and nl_cb_err() callbacks, as each callsite will
+ * do it to suit their needs. See wimaxll_rfkill() for an
+ * example. Any other callback you are supposed to restore to what
+ * it was before.
+ * \param gnl_family_id Generic Netlink Family ID assigned to the device
+ * \param mc_msg Index in the \a gnl_mc array of the "msg"
+ * multicast group.
+ * \param name name of the wimax interface
+ * \param gnl_mc Array of information about the different multicast
+ * groups supported by the device. At least the "msg" group is
+ * always supported. The rest are optional and depend on what the
+ * driver implements.
+ */
+struct wimaxll_handle {
+ struct nl_handle *nlh_tx;
+ int gnl_family_id;
+ unsigned mc_msg;
+ char name[__WIMAXLL_IFNAME_LEN];
+ struct wimaxll_mc_group gnl_mc[WIMAXLL_MC_MAX];
+};
+
+
+/**
+ * Multicast group handle
+ *
+ * \internal
+ *
+ * This structure encapsulates all that we need to read from a single
+ * multicast group. We could have a single handle for doing all, but
+ * by definition of the interface, different multicast groups carry
+ * different traffic (with different needs). Rather than multiplex it
+ * here, we multiplex at the kernel by sending it via an specific pipe
+ * that knows how to handle it already.
+ *
+ * This way the driver can define it's own private pipes (if needed)
+ * for high bandwidth traffic (for example, tracing information)
+ * without affecting the rest of the groups (channels).
+ */
+struct wimaxll_mc_handle {
+ int idx;
+ struct wimaxll_handle *wmx;
+ struct nl_handle *nlh_rx;
+ struct nl_cb *nl_cb;
+ ssize_t result;
+
+ wimaxll_msg_to_user_cb_f msg_to_user_cb;
+ struct wimaxll_gnl_cb_context *msg_to_user_context;
+
+ wimaxll_state_change_cb_f state_change_cb;
+ struct wimaxll_gnl_cb_context *state_change_context;
+};
+
+
+static inline
+void wimaxll_mch_maybe_set_result(struct wimaxll_mc_handle *mch, int val)
+{
+ if (mch->result == -EINPROGRESS)
+ mch->result = val;
+}
+
+
+/* Utilities */
+ssize_t wimaxll_wait_for_rp_result(struct wimaxll_handle *);
+int wimaxll_wait_for_ack(struct wimaxll_handle *);
+int wimaxll_gnl_handle_msg_to_user(struct wimaxll_handle *,
+ struct wimaxll_mc_handle *,
+ struct nl_msg *);
+int wimaxll_gnl_handle_state_change(struct wimaxll_handle *,
+ struct wimaxll_mc_handle *,
+ struct nl_msg *);
+int wimaxll_gnl_error_cb(struct sockaddr_nl *, struct nlmsgerr *, void *);
+struct wimaxll_mc_handle *__wimaxll_get_mc_handle(struct wimaxll_handle *,
+ int pipe_id);
+
+
+#define wimaxll_container_of(pointer, type, member) \
+({ \
+ type *object = NULL; \
+ size_t offset = (void *) &object->member - (void *) object; \
+ (type *) ((void *) pointer - offset); \
+})
+
+
+/*
+ * wimaxll_family_id - Return the associated Generic Netlink family ID
+ *
+ * @wmx: WiMax interface for which to provide the ID.
+ */
+static inline
+int wimaxll_family_id(struct wimaxll_handle *wmx)
+{
+ return wmx->gnl_family_id;
+}
+
+
+void wimaxll_msg(struct wimaxll_handle *, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+
+#endif /* #ifndef __lib_internal_h__ */
diff --git a/lib/libwimax.so.in b/lib/libwimax.so.in
new file mode 100644
index 0000000..8f3f8ba
--- /dev/null
+++ b/lib/libwimax.so.in
@@ -0,0 +1,3 @@
+/* This library is deprecated!!!!
+ In the meantime, do binary compat using aliases. */
+GROUP ( @libdir@/libwimaxll.so )
diff --git a/lib/mc_rx.c b/lib/mc_rx.c
new file mode 100644
index 0000000..c34d687
--- /dev/null
+++ b/lib/mc_rx.c
@@ -0,0 +1,535 @@
+/*
+ * Linux WiMax
+ * Framework for reading from multicast groups
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @defgroup mc_rx Reading form Generic Netlink multicast groups
+ *
+ * The WiMAX stack sends asynchronous traffic (notifications and
+ * messages) to user space through Generic Netlink multicast groups;
+ * thus, when reading that traffic from the kernel, libwimaxll
+ * actually reads from a generic netlink multicast group.
+ *
+ * This allows the kernel to send a single notification that can be
+ * received by an undetermined (and unbound) number of listeners. As
+ * well, this also allows a very flexible way to multiplex different
+ * channels without affecting all the listeners.
+ *
+ * What is called a \e pipe is mapped over one of these multicast
+ * groups.
+ *
+ * \b Example:
+ *
+ * If a driver wants to send tracing information to an application in
+ * user space for analysis, it can create a new \e pipe (Generic
+ * Netlink multicast group) and send it over there.
+ *
+ * The application can listen to it and its traffic volume won't
+ * affect other applications listening to other events coming from the
+ * same device. Some of these other applications could not be ready
+ * ready to cope with such a high traffic.
+ *
+ * If the same model were implemented just using different netlink
+ * messages, all applications listening to events from the driver
+ * would be awakened every time any kind of message were sent, even if
+ * they do not need to listen to some of those messages.
+ *
+ * \warning This is a \b very \b low level interface that is for
+ * internal use.
+ *
+ * \warning If you have to use it in an application, it probably means
+ * something is wrong.
+ *
+ * \warning You might want to use higher level messaging interfaces,
+ * such as the \ref the_pipe_interface_group "the pipe interface"
+ * or the \ref the_messaging_interface "the messaging interface".
+ *
+ * \section usage Usage
+ *
+ * The functions provided by this interface are almost identical than
+ * those of the \ref the_pipe_interface_group "pipe interface". The
+ * main difference is that wimaxll_mc_rx_read() operates at a lower
+ * level.
+ *
+ * \code
+ * int mc_handle;
+ * ssize_t bytes;
+ * ...
+ * mc_handle = wimaxll_mc_rx_open(wimaxll_handle, "name");
+ * ...
+ * bytes = wimaxll_mc_rx_read(wimaxll_handle, mc_handle);
+ * ...
+ * wimaxll_mc_rx_close(wimaxll_handle, mc_handle);
+ * \endcode
+ *
+ * \a my_callback is a function that will be called for every valid
+ * message received from the kernel on a single call to
+ * wimaxll_mc_rx_read().
+ *
+ * Internally, each \e open pipe/multicast-group contains the list of
+ * callbacks for each known message. This is used a look up table for
+ * executing them on reception.
+ *
+ * \section roadmap Roadmap
+ *
+ * \code
+ *
+ * wimaxll_mc_rx_open()
+ * wimaxll_mc_idx_by_name()
+ *
+ * wimaxll_mc_rx_read()
+ * nl_recvmsgs()
+ * wimaxll_seq_check_cb()
+ * wimaxll_gnl_error_cb()
+ * wimaxll_gnl_cb()
+ * wimaxll_gnl_handle_state_change()
+ * wimaxll_gnl_handle_msg_to_user()
+ * wimaxll_mch_maybe_set_result()
+ *
+ * wimaxll_mc_rx_fd()
+ * __wimaxll_mc_handle()
+ * wimaxll_mc_rx_close()
+ * \endcode
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+#include <linux/types.h>
+#include <netlink/msg.h>
+#include <netlink/genl/genl.h>
+#include <wimaxll.h>
+#include "internal.h"
+#define D_LOCAL 0
+#include "debug.h"
+
+
+static
+/**
+ * Lookup the index for a named multicast group
+ *
+ * \param wmx WiMAX device handle
+ * \param name Name of the multicast group to lookup.
+ * \return On success, non-zero positive index for the multicast
+ * group; on error, negative errno code.
+ *
+ * Look up the index of the named multicast group in the cache
+ * obtained at wimaxll_open() time.
+ *
+ * \internal
+ * \ingroup mc_rx
+ * \fn int wimaxll_mc_idx_by_name(struct wimaxll_handle *wmx, const char *name)
+ */
+int wimaxll_mc_idx_by_name(struct wimaxll_handle *wmx, const char *name)
+{
+ unsigned cnt;
+ for (cnt = 0; cnt < WIMAXLL_MC_MAX; cnt++)
+ if (!strcmp(wmx->gnl_mc[cnt].name, name))
+ return cnt;
+ return -EPROTONOSUPPORT;
+}
+
+
+/*
+ * Netlink callback for (disabled) sequence check
+ *
+ * When reading from multicast groups ignore the sequence check, as
+ * they are events (as indicated by the netlink documentation; see the
+ * documentation on nl_disable_sequence_check(), for example here:
+ * http://people.suug.ch/~tgr/libnl/doc-1.1/
+ * group__socket.html#g0ff2f43147e3a4547f7109578b3ca422).
+ *
+ * We need to do this \e manually, as we are using a new callback set
+ * group and thus the libnl defaults set by
+ * nl_disable_sequence_check() don't apply.
+ */
+static
+int wimaxll_seq_check_cb(struct nl_msg *msg, void *arg)
+{
+ return NL_OK;
+}
+
+
+static
+/**
+ * Callback to process a (succesful) message coming from generic
+ * netlink
+ *
+ * \internal
+ *
+ * Called by nl_recvmsgs() when a valid message is received. We
+ * multiplex and handle messages that are known to the library. If the
+ * message is unknown, do nothing other than setting -ENODATA.
+ *
+ * When reading from a pipe with wimaxll_pipe_read(), -ENODATA is
+ * considered a retryable error -- effectively, the message is
+ * skipped.
+ *
+ * \fn int wimaxll_gnl_cb(struct nl_msg *msg, void *_mch)
+ */
+int wimaxll_gnl_cb(struct nl_msg *msg, void *_mch)
+{
+ ssize_t result;
+ struct wimaxll_mc_handle *mch = _mch;
+ struct wimaxll_handle *wmx = mch->wmx;
+ struct nlmsghdr *nl_hdr;
+ struct genlmsghdr *gnl_hdr;
+
+ d_fnstart(7, wmx, "(msg %p mch %p)\n", msg, mch);
+ nl_hdr = nlmsg_hdr(msg);
+ gnl_hdr = nlmsg_data(nl_hdr);
+
+ if (gnl_hdr->cmd >= WIMAX_GNL_OP_MAX)
+ goto error_unknown_msg;
+
+ switch (gnl_hdr->cmd) {
+ case WIMAX_GNL_OP_MSG_TO_USER:
+ if (mch->msg_to_user_cb)
+ result = wimaxll_gnl_handle_msg_to_user(wmx, mch, msg);
+ else
+ goto out_no_handler;
+ break;
+ case WIMAX_GNL_RE_STATE_CHANGE:
+ if (mch->state_change_cb)
+ result = wimaxll_gnl_handle_state_change(wmx, mch, msg);
+ else
+ goto out_no_handler;
+ break;
+ default:
+ goto error_unknown_msg;
+ }
+ wimaxll_mch_maybe_set_result(mch, 0);
+ d_fnend(7, wmx, "(msg %p mch %p) = %zd\n", msg, mch, result);
+ return result;
+
+error_unknown_msg:
+ d_printf(1, wmx, "E: %s: received unknown gnl message %d\n",
+ __func__, gnl_hdr->cmd);
+out_no_handler:
+ wimaxll_mch_maybe_set_result(mch, -ENODATA);
+ result = NL_SKIP;
+ d_fnend(7, wmx, "(msg %p mch %p) = %zd\n", msg, mch, result);
+ return result;
+}
+
+
+/**
+ * Open a handle for reception from a multicast group
+ *
+ * \param wmx WiMAX device handle
+ * \param mc_name Name of the multicast group that has to be opened
+ *
+ * \return If successful, a non-negative handle number (\e { the
+ * multicast group descriptor}), to be given to other functions
+ * for actual operation. In case of error, a negative errno code.
+ *
+ * Allocates a handle to use for reception of data on from a single
+ * multicast group.
+ *
+ * Only one handle may be opened at the same time to each multicast
+ * group.
+ *
+ * \ingroup mc_rx
+ */
+int wimaxll_mc_rx_open(struct wimaxll_handle *wmx,
+ const char *mc_name)
+{
+ int result, idx;
+ struct wimaxll_mc_handle *mch;
+
+ d_fnstart(3, wmx, "(wmx %p mc_name %s)\n", wmx, mc_name);
+ idx = wimaxll_mc_idx_by_name(wmx, mc_name);
+ if (idx < 0) {
+ result = idx;
+ wimaxll_msg(wmx, "E: mc group \"%s\" "
+ "not supported: %d\n", mc_name, result);
+ goto error_mc_idx_by_name;
+ }
+ d_printf(2, wmx, "D: idx is %d\n", idx);
+ result = -EBUSY;
+ if (wmx->gnl_mc[idx].mch) {
+ wimaxll_msg(wmx, "E: BUG! trying to open handle to multicast "
+ "group \"%s\", which is already open\n", mc_name);
+ goto error_reopen;
+ }
+
+ /* Alloc a new multicast group handle */
+ result = -ENOMEM;
+ mch = malloc(sizeof(*mch));
+ if (mch == NULL) {
+ wimaxll_msg(wmx, "E: mc group %s: cannot allocate handle\n",
+ mc_name);
+ goto error_alloc;
+ }
+ memset(mch, 0, sizeof(*mch));
+ mch->wmx = wmx;
+ mch->nlh_rx = nl_handle_alloc();
+ if (mch->nlh_rx == NULL) {
+ result = nl_get_errno();
+ wimaxll_msg(wmx, "E: mc group %s: cannot allocate RX netlink "
+ "handle: %d\n", mc_name, result);
+ goto error_nl_handle_alloc_rx;
+ }
+ result = nl_connect(mch->nlh_rx, NETLINK_GENERIC);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: mc group %s: cannot connect RX netlink: "
+ "%d\n", mc_name, result);
+ goto error_nl_connect_rx;
+ }
+
+ result = nl_socket_add_membership(mch->nlh_rx, wmx->gnl_mc[idx].id);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: mc group %s: cannot join multicast group "
+ "%u: %d\n", mc_name, wmx->gnl_mc[idx].id, result);
+ goto error_nl_add_membership;
+ }
+
+ mch->nl_cb = nl_cb_alloc(NL_CB_VERBOSE);
+ if (mch->nl_cb == NULL) {
+ result = -ENOMEM;
+ wimaxll_msg(wmx, "E: mc group %s: cannot allocate callback\n",
+ mc_name);
+ goto error_cb_alloc;
+ }
+
+ nl_cb_set(mch->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+ wimaxll_seq_check_cb, NULL);
+ nl_cb_set(mch->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, wimaxll_gnl_cb, mch);
+ nl_cb_err(mch->nl_cb, NL_CB_CUSTOM, wimaxll_gnl_error_cb, mch);
+ wmx->gnl_mc[idx].mch = mch;
+ d_fnend(3, wmx, "(wmx %p mc_name %s) = %d\n", wmx, mc_name, idx);
+ return idx;
+
+error_cb_alloc:
+ /* No need to drop membership, it is removed when we close the
+ * handle */
+error_nl_add_membership:
+ nl_close(mch->nlh_rx);
+error_nl_connect_rx:
+ nl_handle_destroy(mch->nlh_rx);
+error_nl_handle_alloc_rx:
+ free(mch);
+error_alloc:
+error_reopen:
+error_mc_idx_by_name:
+ d_fnend(3, wmx, "(wmx %p mc_name %s) = %d\n", wmx, mc_name, result);
+ return result;
+}
+
+
+/**
+ * Close a multicast group handle
+ *
+ * \param wmx WiMAX handle
+ * \param idx Multicast group handle (as returned by wimaxll_mc_rx_open()).
+ *
+ * Releases resources associated to open multicast group handle.
+ *
+ * \ingroup mc_rx
+ */
+void wimaxll_mc_rx_close(struct wimaxll_handle *wmx, unsigned idx)
+{
+ struct wimaxll_mc_handle *mch;
+ d_fnstart(3, wmx, "(wmx %p idx %u)\n", wmx, idx);
+ if (idx >= WIMAXLL_MC_MAX) {
+ wimaxll_msg(wmx, "E: BUG! multicast group index %u "
+ "higher than allowed maximum %u\n",
+ idx, WIMAXLL_MC_MAX);
+ goto out;
+ }
+ mch = wmx->gnl_mc[idx].mch;
+ wmx->gnl_mc[idx].mch = NULL;
+ nl_cb_put(mch->nl_cb);
+ /* No need to drop handle membership to the msg group, closing
+ * it does it */
+ nl_close(mch->nlh_rx);
+ nl_handle_destroy(mch->nlh_rx);
+ free(mch);
+out:
+ d_fnend(3, wmx, "(wmx %p idx %u) = void\n", wmx, idx);
+}
+
+
+/**
+ * Return the multicast group handle associated to a Pipe ID
+ *
+ * \internal
+ *
+ * \param wmx WiMAX device handle
+ * \param pipe_id Multicast group ID, as returned by
+ * wimaxll_mc_rx_open().
+ * \return file descriptor associated to the multicast group, that can
+ * be fed to functions like select().
+ *
+ * \ingroup mc_rx
+ */
+struct wimaxll_mc_handle *__wimaxll_get_mc_handle(struct wimaxll_handle *wmx,
+ int pipe_id)
+{
+ struct wimaxll_mc_handle *mch = NULL;
+
+ if (pipe_id >= WIMAXLL_MC_MAX) {
+ wimaxll_msg(wmx, "E: BUG! mc group #%u does not exist!\n",
+ pipe_id);
+ goto error;
+ }
+ mch = wmx->gnl_mc[pipe_id].mch;
+ if (mch == NULL) {
+ wimaxll_msg(wmx, "E: BUG! trying to read from non-opened "
+ "mc group #%u\n", pipe_id);
+ goto error;
+ }
+error:
+ return mch;
+}
+
+
+/**
+ * Return the file descriptor associated to a multicast group
+ *
+ * \param wmx WiMAX handle
+ * \param pipe_id Multicast group handle, as returned by
+ * wimaxll_mc_rx_open().
+ * \return file descriptor associated to the multicast group, that can
+ * be fed to functions like select().
+ *
+ * This allows to select() on the file descriptor, which will block
+ * until a message is available, that then can be read with
+ * wimaxll_mc_rx_read().
+ *
+ * \ingroup mc_rx
+ */
+int wimaxll_mc_rx_fd(struct wimaxll_handle *wmx, unsigned pipe_id)
+{
+ int result = -EBADFD;
+ struct wimaxll_mc_handle *mch;
+
+ d_fnstart(3, wmx, "(wmx %p pipe_id %u)\n", wmx, pipe_id);
+ mch = __wimaxll_get_mc_handle(wmx, pipe_id);
+ if (mch != NULL)
+ result = nl_socket_get_fd(mch->nlh_rx);
+ d_fnend(3, wmx, "(wmx %p pipe_id %u) = %zd\n", wmx, pipe_id, result);
+ return result;
+}
+
+
+/**
+ * Read from a multicast group
+ *
+ * \param wmx WiMAX device handle
+ * \param index Multicast group handle, as returned by
+ * wimaxll_mc_rx_open().
+ * \return Value returned by the callback functions (depending on the
+ * implementation of the callback). On error, a negative errno
+ * code:
+ *
+ * -%EINPROGRESS: the message was not received.
+ *
+ * -%ENODATA: messages were received, but none of the known types.
+ *
+ * Read one or more messages from a multicast group and for each valid
+ * one, execute the callbacks set in the multi cast handle.
+ *
+ * The callbacks are expected to handle the messages and set
+ * information in the context specific to the mc handle
+ * (mch->cb_ctx). In case of any type of errors (cb_ctx.result < 0),
+ * it is expected that no resources will be tied to the context.
+ *
+ * \remarks This is a blocking call.
+ *
+ * \ingroup mc_rx
+ *
+ * \internal
+ *
+ * This calls nl_recvmsgs() on the handle specific to a multi-cast
+ * group; wimaxll_gnl_cb() will be called for succesfully received
+ * generic netlink messages from the kernel and execute the callbacks
+ * for each.
+ */
+ssize_t wimaxll_mc_rx_read(struct wimaxll_handle *wmx, unsigned index)
+{
+ ssize_t result;
+ struct wimaxll_mc_handle *mch;
+
+ d_fnstart(3, wmx, "(wmx %p index %u)\n", wmx, index);
+ if (index >= WIMAXLL_MC_MAX) {
+ wimaxll_msg(wmx, "E: BUG! mc group #%u does not exist!\n",
+ index);
+ result = -EINVAL;
+ goto error_bad_index;
+ }
+ mch = wmx->gnl_mc[index].mch;
+ if (mch == NULL) {
+ wimaxll_msg(wmx, "E: BUG! trying to read from non-opened "
+ "mc group #%u\n", index);
+ result = -EBADF;
+ goto error_not_open;
+ }
+
+ /*
+ * The reading and processing happens here
+ *
+ * libnl's nl_recvmsgs() will read and call the different
+ * callbacks we specified at wimaxll_mc_rx_open() time. That's
+ * where the processing of the message content is done.
+ */
+ mch->result = -EINPROGRESS;
+ result = nl_recvmsgs(mch->nlh_rx, mch->nl_cb);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: %s: nl_recvmgsgs failed: %d\n",
+ __func__, result);
+ goto error_nl_recvmsgs;
+ }
+ result = mch->result;
+ if (result == -EINPROGRESS) {
+ wimaxll_msg(wmx, "E: %s: no messages parsed\n", __func__);
+ goto error_data;
+ }
+ /* No complains on error; the kernel might just be sending an
+ * error out; pass it through. */
+error_data:
+error_nl_recvmsgs:
+error_not_open:
+error_bad_index:
+ d_fnend(3, wmx, "(wmx %p index %u) = %zd\n", wmx, index, result);
+ return result;
+}
+
+void wimax_mc_rx_open() __attribute__ ((weak, alias("wimaxll_mc_rx_open")));
+void wimax_mc_rx_fd() __attribute__ ((weak, alias("wimaxll_mc_rx_fd")));
+void wimax_mc_rx_close() __attribute__ ((weak, alias("wimaxll_mc_rx_close")));
+void wimax_mc_rx_read() __attribute__ ((weak, alias("wimaxll_mc_rx_read")));
diff --git a/lib/op-msg.c b/lib/op-msg.c
new file mode 100644
index 0000000..73a2daa
--- /dev/null
+++ b/lib/op-msg.c
@@ -0,0 +1,565 @@
+/*
+ * Linux WiMax
+ * Messaging interface implementation
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * \defgroup the_messaging_interface The message interface
+ *
+ * This is a payload agnostic message interface for communication
+ * between the WiMAX kernel drivers and user space applications.
+ *
+ * This interfaces builds on the \e kernel-to-user unidirectional \ref
+ * the_pipe_interface_group "pipe interface". It writes data to the default
+ * \e message pipe by sending it to the WiMAX kernel stack, which
+ * passes it to the driver using the \e wimax_dev->op_msg_from_user()
+ * call.
+ *
+ * Only the default \e message pipe is bidirectional; WiMAX kernel
+ * drivers receive messages sent with wimax_msg_write().
+ *
+ * \note The wimaxll_msg_fd() and wimaxll_msg_read() functions operate
+ * on the default \e message pipe, being convenience functions for
+ * wimaxll_pipe_fd() and wimaxll_pipe_msg_read().
+ *
+ * To wait for a message from the driver:
+ *
+ * @code
+ * void *msg;
+ * ...
+ * size = wimaxll_msg_read(wmx, &msg);
+ * @endcode
+ *
+ * Note this call is synchronous and blocking, and won't timeout. You
+ * can put it on a thread to emulate asynchrony (see \ref
+ * multithreading), but still it is quite difficult to integrate it in
+ * an event loop. Read on for mainloop integration options.
+ *
+ * In \e msg you get a pointer to a dynamically allocated (by \e
+ * libwimaxll) area with the message payload. When the application is
+ * done processing the message, call:
+ *
+ * @code
+ * wimaxll_msg_free(msg);
+ * @endcode
+ *
+ * To write messages to the driver:
+ *
+ * @code
+ * wimaxll_msg_write(wmx, buf, buf_size);
+ * @endcode
+ *
+ * where \a buf points to where the message is stored.
+ *
+ * \note Messages can be written to the driver \e only over the
+ * default \e message pipe. Thus, no wimax_pipe_msg_write()
+ * function is available.
+ *
+ * All functions return negative \a errno codes on error.
+ *
+ * To integrate message reception into a mainloop, \ref callbacks
+ * "callbacks" and select() should be used. The file descriptor
+ * associated to the default \e message \e pipe can be obtained with
+ * wimaxll_msg_fd(). When there is activity on the file descriptor,
+ * wimaxll_pipe_read() should be called on the default pipe:
+ *
+ * \code
+ * wimax_pipe_read(wmx, wimax_msg_pipe_id(wmx));
+ * \endcode
+ *
+ * this will, as explained in \ref receiving, for each received
+ * notification, execute its callback.
+ *
+ * The callback for reception of messages from the WiMAX kernel stack
+ * can be set with wimaxll_pipe_set_cb_msg_to_user() (using as \e
+ * pipe_id the value returned by wimax_msg_pipe_id()). For detailed
+ * information on the message reception callback, see the definition
+ * of \ref wimaxll_msg_to_user_cb_f.
+ *
+ * The kernel WiMAX stack allows drivers to create any number of pipes
+ * on which to send information (messages) to user space. This
+ * interface provides means to read those messages, which are mostly
+ * device specific.
+ *
+ * This is a lower level interface than \ref the_messaging_interface
+ * "the messaging interface"; however, it operates similarly.
+ *
+ * @code
+ * void *msg;
+ * ...
+ * handle = wimaxll_pipe_open(wmx, "PIPENAME");
+ * ...
+ * wimaxll_pipe_msg_read(wmx, handle, &msg);
+ * ...
+ * wimaxll_msg_free(msg);
+ * ...
+ * wimaxll_pipe_close(wmx, handle);
+ * @endcode
+ *
+ * More information about the details of this interface can be found
+ * \ref the_pipe_interface_group "here".
+ *
+ * \note These pipes are not bidirectional.
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+#include <linux/types.h>
+#include <netlink/msg.h>
+#include <netlink/genl/genl.h>
+#include <wimaxll.h>
+#include "internal.h"
+#define D_LOCAL 0
+#include "debug.h"
+
+
+
+/**
+ * WIMAX_GNL_MSG_FROM_USER: policy specification
+ *
+ * \ingroup the_messaging_interface
+ * \internal
+ *
+ * Authoritative reference for this is at the kernel code,
+ * drivers/net/wimax/op-msg.c.
+ *
+ */
+static
+struct nla_policy wimaxll_gnl_msg_from_user_policy[WIMAX_GNL_ATTR_MAX + 1] = {
+ [WIMAX_GNL_MSG_DATA] = {
+ .type = NLA_UNSPEC,
+ },
+};
+
+
+/**
+ * Callback to process an WIMAX_GNL_OP_MSG_TO_USER from the kernel
+ *
+ * \internal
+ * \ingroup the_messaging_interface
+ *
+ * \param wmx WiMAX device handle
+ * \param mch Pointer to \c struct wimaxll_mc_handle
+ * \param msg Pointer to netlink message
+ * \return \c enum nl_cb_action
+ *
+ * wimaxll_mc_rx_read() calls libnl's nl_recvmsgs() to receive messages;
+ * when a valid message is received, it goes into a loop that selects
+ * a callback to run for each type of message and it will call this
+ * function.
+ *
+ * This just expects a _MSG_TO_USER message, whose payload is what
+ * has to be passed to the caller. Because nl_recvmsgs() will free the
+ * message data, a new buffer has to be allocated and copied (a patch
+ * has been merged already to future versions of libnl that helps in
+ * this).
+ *
+ * It stores the buffer and size (or result in case of error) in the
+ * context passed in \e mch->msg_to_user_context.
+ */
+int wimaxll_gnl_handle_msg_to_user(struct wimaxll_handle *wmx,
+ struct wimaxll_mc_handle *mch,
+ struct nl_msg *msg)
+{
+ size_t size;
+ ssize_t result;
+ struct nlmsghdr *nl_hdr;
+ struct genlmsghdr *gnl_hdr;
+ struct nlattr *tb[WIMAX_GNL_ATTR_MAX+1];
+ struct wimaxll_gnl_cb_context *ctx = mch->msg_to_user_context;
+ void *data;
+
+ d_fnstart(7, wmx, "(wmx %p mch %p msg %p)\n", wmx, mch, msg);
+ nl_hdr = nlmsg_hdr(msg);
+ gnl_hdr = nlmsg_data(nl_hdr);
+
+ assert(gnl_hdr->cmd == WIMAX_GNL_OP_MSG_TO_USER);
+
+ /* Parse the attributes */
+ result = genlmsg_parse(nl_hdr, 0, tb, WIMAX_GNL_ATTR_MAX,
+ wimaxll_gnl_msg_from_user_policy);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: %s: genlmsg_parse() failed: %d\n",
+ __func__, result);
+ wimaxll_cb_context_set_result(ctx, result);
+ result = NL_SKIP;
+ goto error_parse;
+ }
+ if (tb[WIMAX_GNL_MSG_DATA] == NULL) {
+ wimaxll_msg(wmx, "E: %s: cannot find MSG_DATA attribute\n",
+ __func__);
+ wimaxll_cb_context_set_result(ctx, -ENXIO);
+ result = NL_SKIP;
+ goto error_no_attrs;
+
+ }
+ result = (ssize_t) nla_get_u64(tb[WIMAX_GNL_RESULT_CODE]);
+ wimaxll_cb_context_set_result(ctx, result);
+
+ size = nla_len(tb[WIMAX_GNL_MSG_DATA]);
+ data = nla_data(tb[WIMAX_GNL_MSG_DATA]);
+
+ d_printf(1, wmx, "D: CRX genlmsghdr cmd %u version %u\n",
+ gnl_hdr->cmd, gnl_hdr->version);
+ d_printf(1, wmx, "D: CRX msg from kernel %u bytes\n", size);
+ d_dump(2, wmx, data, size);
+
+ /* This was set by whoever called nl_recmvsgs (or
+ * wimaxll_mc_rx_read() or wimaxll_pipe_read()) */
+ if (mch->msg_to_user_cb(wmx, ctx, data, size) == -EBUSY)
+ result = NL_STOP;
+ else
+ result = NL_OK;
+error_no_attrs:
+error_parse:
+ d_fnend(7, wmx, "(wmx %p mch %p msg %p) = %d\n", wmx, mch, msg, result);
+ return result;
+}
+
+
+struct wimaxll_cb_msg_to_user_context {
+ struct wimaxll_gnl_cb_context ctx;
+ void *data;
+};
+
+
+/*
+ * Default handling of messages
+ *
+ * When someone calls wimaxll_msg_read() or wimaxll_pipe_msg_read(), those
+ * functions set this default callback, which will just copy the data
+ * to a buffer and pass that pointer to the caller along with the size.
+ */
+static
+int wimaxll_cb_msg_to_user(struct wimaxll_handle *wmx,
+ struct wimaxll_gnl_cb_context *ctx,
+ const char *data, size_t data_size)
+{
+ struct wimaxll_cb_msg_to_user_context *mtu_ctx =
+ wimaxll_container_of(
+ ctx, struct wimaxll_cb_msg_to_user_context, ctx);
+
+ if (mtu_ctx->data)
+ return -EBUSY;
+ mtu_ctx->data = malloc(data_size);
+ if (mtu_ctx->data) {
+ memcpy(mtu_ctx->data, data, data_size);
+ ctx->result = data_size;
+ } else
+ ctx->result = -ENOMEM;
+ return 0;
+}
+
+
+/**
+ * Read a message from any WiMAX kernel-user pipe
+ *
+ * \param wmx WiMAX device handle
+ * \param pipe_id Pipe to read from (as returned by
+ * wimaxll_pipe_open()). To use the default pipe, indicate
+ * use wimax_msg_pipe_id().
+ * \param buf Somewhere where to store the pointer to the message data.
+ * \return If successful, a positive (and \c *buf set) or zero size of
+ * the message; on error, a negative \a errno code (\c buf
+ * n/a).
+ *
+ * Returns a message allocated in \c *buf as sent by the kernel via
+ * the indicated pipe. The message is allocated by the
+ * library and owned by the caller. When done, it has to be freed with
+ * wimaxll_msg_free() to release the space allocated to it.
+ *
+ * \note This is a blocking call.
+ *
+ * \ingroup the_messaging_interface
+ */
+ssize_t wimaxll_pipe_msg_read(struct wimaxll_handle *wmx, unsigned pipe_id,
+ void **buf)
+{
+ ssize_t result;
+ struct wimaxll_cb_msg_to_user_context mtu_ctx = {
+ .ctx = WIMAXLL_GNL_CB_CONTEXT_INIT(wmx),
+ .data = NULL,
+ };
+ wimaxll_msg_to_user_cb_f prev_cb = NULL;
+ struct wimaxll_gnl_cb_context *prev_priv = NULL;
+
+ d_fnstart(3, wmx, "(wmx %p buf %p)\n", wmx, buf);
+ wimaxll_pipe_get_cb_msg_to_user(wmx, pipe_id, &prev_cb, &prev_priv);
+ wimaxll_pipe_set_cb_msg_to_user(wmx, pipe_id,
+ wimaxll_cb_msg_to_user, &mtu_ctx.ctx);
+ result = wimaxll_pipe_read(wmx, pipe_id);
+ if (result >= 0) {
+ *buf = mtu_ctx.data;
+ result = mtu_ctx.ctx.result;
+ }
+ wimaxll_pipe_set_cb_msg_to_user(wmx, pipe_id, prev_cb, prev_priv);
+ d_fnend(3, wmx, "(wmx %p buf %p) = %zd\n", wmx, buf, result);
+ return result;
+}
+
+
+/**
+ * Free a message received with wimaxll_pipe_msg_read() or
+ * wimaxll_msg_read()
+ *
+ * \param msg message pointer returned by wimaxll_pipe_msg_read() or
+ * wimaxll_msg_read().
+ *
+ * \note this function is the same as wimaxll_msg_free()
+ *
+ * \ingroup the_messaging_interface
+ */
+void wimaxll_pipe_msg_free(void *msg)
+{
+ d_fnstart(3, NULL, "(msg %p)\n", msg);
+ free(msg);
+ d_fnend(3, NULL, "(msg %p) = void\n", msg);
+}
+
+
+/**
+ * Return the file descriptor associated to the default \e message pipe
+ *
+ * \param wmx WiMAX device handle
+ * \return file descriptor associated to the messaging group, that can
+ * be fed to functions like select().
+ *
+ * This allows to select() on the file descriptor, which will block
+ * until a message is available, that then can be read with
+ * wimaxll_pipe_read().
+ *
+ * \ingroup the_messaging_interface
+ */
+int wimaxll_msg_fd(struct wimaxll_handle *wmx)
+{
+ return wimaxll_mc_rx_fd(wmx, wmx->mc_msg);
+}
+
+
+/**
+ * Read a message from the WiMAX default \e message pipe.
+ *
+ * \param wmx WiMAX device handle
+ * \param buf Somewhere where to store the pointer to the message data.
+ * \return If successful, a positive (and \c *buf set) or zero size of
+ * the message; on error, a negative \a errno code (\c buf
+ * n/a).
+ *
+ * Returns a message allocated in \c *buf as sent by the kernel via
+ * the default \e message pipe. The message is allocated by the
+ * library and owned by the caller. When done, it has to be freed with
+ * wimaxll_msg_free() to release the space allocated to it.
+ *
+ * \note This is a blocking call.
+ *
+ * \ingroup the_messaging_interface
+ */
+ssize_t wimaxll_msg_read(struct wimaxll_handle *wmx, void **buf)
+{
+ return wimaxll_pipe_msg_read(wmx, wmx->mc_msg, buf);
+}
+
+
+/**
+ * Free a message received with wimaxll_pipe_msg_read() or
+ * wimaxll_msg_read()
+ *
+ * \param msg message pointer returned by wimaxll_pipe_msg_read() or
+ * wimaxll_msg_read().
+ *
+ * \note this function is the same as wimaxll_pipe_msg_free()
+ *
+ * \ingroup the_messaging_interface
+ */
+void wimaxll_msg_free(void *msg)
+{
+ wimaxll_pipe_msg_free(msg);
+}
+
+
+/**
+ * Send a driver-specific message to a WiMAX device
+ *
+ * \param wmx wimax device descriptor
+ * \param buf Pointer to the wimax message.
+ * \param size size of the message.
+ *
+ * \return 0 if ok < 0 errno code on error. On error it is assumed
+ * the message wasn't delivered.
+ *
+ * Sends a data buffer down to the kernel driver. The format of the
+ * message is driver specific.
+ *
+ * \note This is a blocking call
+ *
+ * \ingroup the_messaging_interface
+ */
+ssize_t wimaxll_msg_write(struct wimaxll_handle *wmx,
+ const void *buf, size_t size)
+{
+ ssize_t result;
+ struct nl_msg *nl_msg;
+ void *msg;
+
+ d_fnstart(3, wmx, "(wmx %p buf %p size %zu)\n", wmx, buf, size);
+ nl_msg = nlmsg_new();
+ if (nl_msg == NULL) {
+ result = nl_get_errno();
+ wimaxll_msg(wmx, "E: cannot allocate generic netlink "
+ "message: %m\n");
+ goto error_msg_alloc;
+ }
+ msg = genlmsg_put(nl_msg, NL_AUTO_PID, NL_AUTO_SEQ,
+ wimaxll_family_id(wmx), 0, 0,
+ WIMAX_GNL_OP_MSG_FROM_USER, WIMAX_GNL_VERSION);
+ if (msg == NULL) {
+ result = nl_get_errno();
+ wimaxll_msg(wmx, "E: %s: error preparing message: %d\n",
+ __func__, result);
+ goto error_msg_prep;
+ }
+
+ nla_put(nl_msg, WIMAX_GNL_MSG_DATA, size, buf);
+
+ d_printf(5, wmx, "D: CTX nl + genl header:\n");
+ d_dump(5, wmx, nlmsg_hdr(nl_msg),
+ sizeof(struct nlmsghdr) + sizeof(struct genlmsghdr));
+ d_printf(5, wmx, "D: CTX wimax message:\n");
+ d_dump(5, wmx, buf, size);
+
+ result = nl_send_auto_complete(wmx->nlh_tx, nl_msg);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: error sending message: %d\n", result);
+ goto error_msg_send;
+ }
+
+ result = wimaxll_wait_for_ack(wmx); /* Get the ACK from netlink */
+ if (result < 0)
+ wimaxll_msg(wmx, "E: %s: generic netlink ack failed: %d\n",
+ __func__, result);
+error_msg_send:
+error_msg_prep:
+ nlmsg_free(nl_msg);
+error_msg_alloc:
+ d_fnend(3, wmx, "(wmx %p buf %p size %zu) = %zd\n",
+ wmx, buf, size, result);
+ return result;
+}
+
+
+/**
+ * Return the pipe ID for the messaging interface
+ *
+ * @param wmx WiMAX device descriptor
+ * @return Pipe id of the messaging interface, that can be used with
+ * the wimaxll_pipe_*() functions.
+ *
+ * \ingroup the_messaging_interface_group
+ */
+unsigned wimaxll_msg_pipe_id(struct wimaxll_handle *wmx)
+{
+ return wmx->mc_msg;
+}
+
+
+/**
+ * Get the callback and priv pointer for a MSG_TO_USER message
+ *
+ * \param wmx WiMAX handle.
+ * \param pipe_id Pipe on which to listen for the message [as returned
+ * by wimaxll_pipe_open()].
+ * \param cb Where to store the current callback function.
+ * \param context Where to store the private data pointer passed to the
+ * callback.
+ *
+ * \ingroup the_messaging_interface_group
+ */
+void wimaxll_pipe_get_cb_msg_to_user(
+ struct wimaxll_handle *wmx, unsigned pipe_id,
+ wimaxll_msg_to_user_cb_f *cb, struct wimaxll_gnl_cb_context **context)
+{
+ struct wimaxll_mc_handle *mch;
+
+ mch = __wimaxll_get_mc_handle(wmx, pipe_id);
+ if (mch != NULL) {
+ *cb = mch->msg_to_user_cb;
+ *context = mch->msg_to_user_context;
+ }
+}
+
+
+/**
+ * Set the callback and priv pointer for a MSG_TO_USER message
+ *
+ * \param wmx WiMAX handle.
+ * \param pipe_id Pipe on which to listen for the message [as returned
+ * by wimaxll_pipe_open()].
+ * \param cb Callback function to set
+ * \param context Private data pointer to pass to the callback
+ * function (wrap a \a struct wimaxll_gnl_cb_context in your context
+ * struct and pass a pointer to it; then use wimaxll_container_of()
+ * to extract it back).
+ *
+ * \ingroup the_messaging_interface_group
+ */
+void wimaxll_pipe_set_cb_msg_to_user(
+ struct wimaxll_handle *wmx, unsigned pipe_id,
+ wimaxll_msg_to_user_cb_f cb, struct wimaxll_gnl_cb_context *context)
+{
+ struct wimaxll_mc_handle *mch;
+
+ mch = __wimaxll_get_mc_handle(wmx, pipe_id);
+ if (mch != NULL) {
+ mch->msg_to_user_cb = cb;
+ mch->msg_to_user_context = context;
+ }
+}
+
+
+void wimax_msg_fd() __attribute__ ((weak, alias("wimaxll_msg_fd")));
+void wimax_msg_read() __attribute__ ((weak, alias("wimaxll_msg_read")));
+void wimax_msg_write() __attribute__ ((weak, alias("wimaxll_msg_write")));
+void wimax_msg_free() __attribute__ ((weak, alias("wimaxll_msg_free")));
+void wimax_msg_pipe_id() __attribute__ ((weak, alias("wimaxll_msg_pipe_id")));
+void wimax_pipe_msg_read()
+ __attribute__ ((weak, alias("wimaxll_pipe_msg_read")));
+void wimax_pipe_msg_free()
+ __attribute__ ((weak, alias("wimaxll_pipe_msg_free")));
+void wimax_pipe_get_cb_msg_to_user()
+ __attribute__ ((weak, alias("wimaxll_pipe_get_cb_msg_to_user")));
+void wimax_pipe_set_cb_msg_to_user()
+ __attribute__ ((weak, alias("wimaxll_pipe_set_cb_msg_to_user")));
diff --git a/lib/op-open.c b/lib/op-open.c
new file mode 100644
index 0000000..d151284
--- /dev/null
+++ b/lib/op-open.c
@@ -0,0 +1,548 @@
+/*
+ * Linux WiMAX
+ * Opening handles
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @defgroup device_management WiMAX device management
+ *
+ * The main device management operations are wimaxll_open(),
+ * wimaxll_close() and wimax_reset().
+ *
+ * It is allowed to have more than one handle opened at the same
+ * time.
+ *
+ * Use wimaxll_ifname() to obtain the name of the WiMAX interface a
+ * handle is open for.
+ *
+ * \internal
+ * \section Roadmap Roadmap
+ *
+ * \code
+ * wimaxll_open()
+ * __wimaxll_cmd_open()
+ * nl_recvmsgs()
+ * wimaxll_gnl_rp_ifinfo_cb()
+ * __wimaxll_ifinfo_parse_groups()
+ * wimaxll_gnl_error_cb()
+ *
+ * wimaxll_close()
+ * wimaxll_mc_rx_close()
+ * wimaxll_free()
+ *
+ * wimaxll_ifname()
+ * \endcode
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+#include <linux/types.h>
+#include <netlink/msg.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <wimaxll.h>
+#include "internal.h"
+#define D_LOCAL 0
+#include "debug.h"
+
+
+/**
+ * Generic Netlink: IFINFO message policy
+ *
+ * \internal
+ * \ingroup device_management
+ *
+ * Authoritative reference for this is in drivers/net/wimax/op-open.c;
+ * this is just a copy.
+ */
+static
+struct nla_policy wimaxll_gnl_ifinfo_policy[WIMAX_GNL_ATTR_MAX + 1] = {
+ [WIMAX_GNL_IFINFO_MC_GROUPS] = { .type = NLA_NESTED },
+ [WIMAX_GNL_IFINFO_MC_GROUP] = { .type = NLA_NESTED },
+ [WIMAX_GNL_IFINFO_MC_NAME] = {
+ .type = NLA_STRING,
+ .maxlen = GENL_NAMSIZ
+ },
+ [WIMAX_GNL_IFINFO_MC_ID] = { .type = NLA_U16 },
+};
+
+
+/**
+ * Callback context for processing IFINFO messages
+ *
+ * \ingroup device_management
+ * \internal
+ *
+ * All the callbacks store the information they parse from the
+ * messages here; we do it so that only once everything passes with
+ * flying colors, then we commit the information the kernel sent.
+ *
+ * We include a \a struct wimaxll_gnl_cb_context so we can share this
+ * same data structure with the error handler and not require to check
+ * different data in different places.
+ *
+ * gnl_mc stands for Generic Netlink MultiCast group
+ */
+struct wimaxll_ifinfo_context {
+ struct wimaxll_gnl_cb_context gnl;
+ struct wimaxll_mc_group gnl_mc[WIMAXLL_MC_MAX];
+};
+
+
+/**
+ * Parse the list of multicast groups sent as part of a IFINFO reply
+ *
+ * \ingroup device_management
+ * \internal
+ *
+ * \param ctx IFINFO context, containing the WiMAX handle
+ *
+ * \param nla_groups Netlink attribute (type
+ * WIMAXLL_GNL_IFINFO_MC_GROUPS) that contains the list of (nested)
+ * attributes (type WIMAXLL_GNL_IFINFO_MC_GROUP).
+ * Just pass tb[WIMAXLL_GNL_IFINFO_MC_GROUPS]; this function will
+ * check for it to be ok (non-NULL).
+ *
+ * \return 0 if ok, < 0 errno code on error.
+ *
+ * On success, the \a wmx->mc_group array will be cleared and
+ * overwritten with the list of reported groups (and their
+ * IDs).
+ *
+ * On error, nothing is modified.
+ *
+ * The kernel has sent a list of attributes: a nested attribute
+ * (_MC_GROUPS) containing a list of nested attributes (_MC_GROUP)
+ * each with a _MC_NAME and _MC_ID attribute].
+ *
+ * We need to parse it and extract the multicast group data. At least
+ * a multicast group ('reports') has to exist; the rest are optional
+ * to a maximum of WIMAXLL_MC_MAX (without counting 'reports').
+ *
+ * \note The private data for this callback is not an \a struct
+ * wimaxll_mc_handle as most of the other ones!
+ */
+static
+int __wimaxll_ifinfo_parse_groups(struct wimaxll_ifinfo_context *ctx,
+ struct nlattr *nla_groups)
+{
+ int result, remaining, cnt = 0;
+ struct wimaxll_handle *wmx = ctx->gnl.wmx;
+ struct nlattr *nla_group;
+
+ d_fnstart(7, wmx, "(ctx %p [wmx %p] nla_groups %p)\n",
+ ctx, wmx, nla_groups);
+ if (nla_groups == NULL) {
+ wimaxll_msg(wmx, "E: %s: the kernel didn't send a "
+ "WIMAXLL_GNL_IFINFO_MC_GROUPS attribute\n",
+ __func__);
+ result = -EBADR;
+ goto error_no_groups;
+ }
+
+ memset(ctx->gnl_mc, 0, sizeof(ctx->gnl_mc));
+ nla_for_each_nested(nla_group, nla_groups, remaining) {
+ char *name;
+ int id;
+ struct nlattr *tb[WIMAX_GNL_ATTR_MAX+1];
+
+ d_printf(8, wmx, "D: group %d, remaining %d\n",
+ cnt, remaining);
+ result = nla_parse_nested(tb, WIMAX_GNL_ATTR_MAX,
+ nla_group,
+ wimaxll_gnl_ifinfo_policy);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: %s: can't parse "
+ "WIMAX_GNL_MC_GROUP attribute: %d\n",
+ __func__, result);
+ continue;
+ }
+
+ if (tb[WIMAX_GNL_IFINFO_MC_NAME] == NULL) {
+ wimaxll_msg(wmx, "E: %s: multicast group missing "
+ "WIMAX_GNL_IFINFO_MC_NAME attribute\n",
+ __func__);
+ continue;
+ }
+ name = nla_get_string(tb[WIMAX_GNL_IFINFO_MC_NAME]);
+
+ if (tb[WIMAX_GNL_IFINFO_MC_ID] == NULL) {
+ wimaxll_msg(wmx, "E: %s: multicast group missing "
+ "WIMAX_GNL_IFINFO_MC_ID attribute\n",
+ __func__);
+ continue;
+ }
+ id = nla_get_u16(tb[WIMAX_GNL_IFINFO_MC_ID]);
+
+ d_printf(6, wmx, "D: MC group %s:%d\n", name, id);
+ strncpy(ctx->gnl_mc[cnt].name, name,
+ sizeof(ctx->gnl_mc[cnt].name));
+ ctx->gnl_mc[cnt].id = id;
+ cnt++;
+ }
+ result = 0;
+error_no_groups:
+ d_fnend(7, wmx, "(ctx %p [wmx %p] nla_groups %p) = %d\n",
+ ctx, wmx, nla_groups, result);
+ return result;
+}
+
+
+/*
+ * Same as wimaxll_gnl_error_cb(), but takes a different type of
+ * context, so, need another one (fitting an mch in there made little
+ * sense).
+ */
+int wimaxll_gnl_rp_ifinfo_error_cb(struct sockaddr_nl *nla,
+ struct nlmsgerr *nlerr,
+ void *_ctx)
+{
+ struct wimaxll_ifinfo_context *ctx = _ctx;
+ struct wimaxll_handle *wmx = ctx->gnl.wmx;
+
+ d_fnstart(7, wmx, "(nla %p nlnerr %p [%d] ctx %p)\n",
+ nla, nlerr, nlerr->error, _ctx);
+ if (ctx->gnl.result == -EINPROGRESS)
+ ctx->gnl.result = nlerr->error;
+ d_fnend(7, wmx, "(nla %p nlnerr %p [%d] ctx %p) = %d\n",
+ nla, nlerr, nlerr->error, _ctx, NL_STOP);
+ return NL_STOP;
+}
+
+
+/**
+ * Seek for and process a WIMAX_GNL_RP_IFINFO message from the kernel
+ *
+ * \ingroup device_management
+ * \internal
+ *
+ * \param msg Netlink message containing the reply
+ * \param _ctx Pointer to a \a struct wimaxll_gnl_cb_context where the
+ * context will be returned.
+ *
+ * \return 'enum nl_cb_action', NL_OK if there is no error, NL_STOP on
+ * error and _ctx possibly updated.
+ *
+ * This will take a received netlink message, check it is a \a
+ * WIMAX_GNL_RP_IFINFO, parse the contents and store them in an
+ * struct wimaxll_ifinfo_context (for the caller to use later on).
+ */
+static
+int wimaxll_gnl_rp_ifinfo_cb(struct nl_msg *msg, void *_ctx)
+{
+ int result;
+ struct wimaxll_ifinfo_context *ctx = _ctx;
+ struct wimaxll_handle *wmx = ctx->gnl.wmx;
+ struct nlmsghdr *nl_hdr;
+ struct genlmsghdr *genl_hdr;
+ struct nlattr *tb[WIMAX_GNL_ATTR_MAX + 1];
+ unsigned major, minor;
+
+ d_fnstart(7, wmx, "(msg %p ctx %p)\n", msg, ctx);
+ nl_hdr = nlmsg_hdr(msg);
+ genl_hdr = nlmsg_data(nl_hdr);
+
+ if (genl_hdr->cmd != WIMAX_GNL_RP_IFINFO) {
+ ctx->gnl.result = -ENXIO;
+ result = NL_SKIP;
+ d_printf(1, wmx, "D: ignoring unknown reply %d\n",
+ genl_hdr->cmd);
+ goto error_parse;
+ }
+
+ /* Check version compatibility -- check include/linux/wimax.h
+ * for a complete description. The idea is to allow for good
+ * expandability of the interface without causing breakage. */
+ major = genl_hdr->version / 10;
+ minor = genl_hdr->version % 10;
+ if (major != WIMAX_GNL_VERSION / 10) {
+ ctx->gnl.result = -EBADR;
+ result = NL_SKIP;
+ wimaxll_msg(wmx, "E: kernel's major WiMAX GNL interface "
+ "version (%d) is different that supported %d; "
+ "aborting\n", major, WIMAX_GNL_VERSION / 10);
+ goto error_bad_major;
+ }
+ if (minor < WIMAX_GNL_VERSION % 10)
+ wimaxll_msg(wmx, "W: kernel's minor WiMAX GNL interface "
+ "version (%d) is lower that supported %d; things "
+ "might not work\n", minor, WIMAX_GNL_VERSION % 10);
+
+ /* Parse the attributes */
+ result = genlmsg_parse(nl_hdr, 0, tb, WIMAX_GNL_IFINFO_MAX,
+ wimaxll_gnl_ifinfo_policy);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: %s: genlmsg_parse() failed: %d\n",
+ __func__, result);
+ ctx->gnl.result = result;
+ result = NL_SKIP;
+ goto error_parse;
+ }
+ result = __wimaxll_ifinfo_parse_groups(ctx,
+ tb[WIMAX_GNL_IFINFO_MC_GROUPS]);
+ if (result < 0) {
+ ctx->gnl.result = result;
+ result = NL_SKIP;
+ } else {
+ ctx->gnl.result = 0;
+ result = NL_OK;
+ }
+error_parse:
+error_bad_major:
+ d_fnend(7, wmx, "(msg %p ctx %p) = %d\n", msg, ctx, result);
+ return result;
+}
+
+
+static
+int __wimaxll_cmd_open(struct wimaxll_handle *wmx)
+{
+ int result;
+ struct nl_msg *msg;
+ struct nl_cb *cb;
+ struct wimaxll_ifinfo_context ctx;
+
+ d_fnstart(5, wmx, "(wmx %p)\n", wmx);
+ msg = nlmsg_new();
+ if (msg == NULL) {
+ result = -errno;
+ wimaxll_msg(wmx, "E: %s: cannot allocate generic netlink "
+ "message: %m\n", __func__);
+ goto error_msg_alloc;
+ }
+ if (genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ,
+ wimaxll_family_id(wmx), 0, 0,
+ WIMAX_GNL_OP_OPEN, WIMAX_GNL_VERSION) == NULL) {
+ result = -errno;
+ wimaxll_msg(wmx, "E: %s: error preparing message: %m\n",
+ __func__);
+ goto error_msg_prep;
+ }
+ result = nl_send_auto_complete(wmx->nlh_tx, msg);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: %s: error sending message: %d\n",
+ __func__, result);
+ goto error_msg_send;
+ }
+
+ /* Read the reply, that includes a WIMAX_GNL_RP_IFINFO message
+ *
+ * We need to set the call back error handler, so we get the
+ * default cb handler and modify it.
+ */
+ ctx.gnl.wmx = wmx;
+ ctx.gnl.result = -EINPROGRESS;
+ cb = nl_socket_get_cb(wmx->nlh_tx);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
+ wimaxll_gnl_rp_ifinfo_cb, &ctx);
+ nl_cb_err(cb, NL_CB_CUSTOM, wimaxll_gnl_rp_ifinfo_error_cb, &ctx.gnl);
+ nl_recvmsgs_default(wmx->nlh_tx);
+ nl_cb_put(cb);
+ result = ctx.gnl.result;
+ if (result >= 0)
+ nl_wait_for_ack(wmx->nlh_tx);
+ if (result == -EINPROGRESS)
+ wimaxll_msg(wmx, "E: %s: the kernel didn't reply with a "
+ "WIMAX_GNL_RP_IFINFO message\n", __func__);
+ d_printf(1, wmx, "D: processing result is %d\n", result);
+
+ /* All fine and dandy, commit the data */
+ memcpy(wmx->gnl_mc, ctx.gnl_mc, sizeof(ctx.gnl_mc));
+error_msg_prep:
+error_msg_send:
+ nlmsg_free(msg);
+error_msg_alloc:
+ d_fnend(5, wmx, "(wmx %p) = %d\n", wmx, result);
+ return result;
+}
+
+
+static
+void wimaxll_free(struct wimaxll_handle *wmx)
+{
+ free(wmx);
+}
+
+
+/**
+ * Open a handle to the WiMAX control interface in the kernel
+ *
+ * \param device device name of the WiMAX network interface
+ * \return WiMAX device handle on success; on error, %NULL is returned
+ * and the \a errno variable is updated with a corresponding
+ * negative value.
+ *
+ * When opening the handle to the device, a basic check of API
+ * versioning will be done. If the kernel interface has a different
+ * major version, the \c wimaxll_open() call will fail (existing
+ * interfaces modified or removed). A higher kernel minor version is
+ * allowed (new interfaces added); a lower kernel minor version is not
+ * (the library needs interfaces that are not in the kernel).
+ *
+ * \ingroup device_management
+ * \internal
+ *
+ * Allocates the netlink handles needed to talk to the kernel. With
+ * that, looks up the Generic Netlink Family ID associated (if none,
+ * it's not a WiMAX device). This is done by querying generic netlink
+ * for a family called "WiMAX <DEVNAME>".
+ *
+ * An open command is issued to get and process interface information
+ * (like multicast group mappings, etc). This also does an interface
+ * versioning verification.
+ *
+ * The bulk of this code is in the parsing of the generic netlink
+ * reply that the \a WIMAX_GNL_OP_OPEN command returns (\a
+ * WIMAX_GNL_RP_IFINFO) with information about the WiMAX control
+ * interface.
+ *
+ * We process said reply using the \e libnl callback mechanism,
+ * invoked by __wimaxll_cmd_open(). All the information is stored in a
+ * struct wimaxll_ifinfo_context by the callbacks. When the callback
+ * (and thus message) processing finishes, __wimaxll_cmd_open(), if all
+ * successful, will commit the information from the context to the
+ * handle. On error, nothing is modified.
+ *
+ * \note Because events are going to ben processed, sequence checks
+ * have to be disabled (as indicated by the generic netlink
+ * documentation).
+ */
+struct wimaxll_handle *wimaxll_open(const char *device)
+{
+ int result;
+ struct wimaxll_handle *wmx;
+ char buf[64];
+
+ d_fnstart(3, NULL, "(device %s)\n", device);
+ result = ENOMEM;
+ wmx = malloc(sizeof(*wmx));
+ if (wmx == NULL) {
+ wimaxll_msg(NULL, "E: cannot allocate WiMax handle: %m\n");
+ goto error_gnl_handle_alloc;
+ }
+ memset(wmx, 0, sizeof(*wmx));
+ strncpy(wmx->name, device, sizeof(wmx->name));
+
+ /* Setup the TX side */
+ wmx->nlh_tx = nl_handle_alloc();
+ if (wmx->nlh_tx == NULL) {
+ result = nl_get_errno();
+ wimaxll_msg(wmx, "E: cannot open TX netlink handle: %d\n",
+ result);
+ goto error_nl_handle_alloc_tx;
+ }
+ result = nl_connect(wmx->nlh_tx, NETLINK_GENERIC);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: cannot connect TX netlink: %d\n", result);
+ goto error_nl_connect_tx;
+ }
+
+ /* Lookup the generic netlink family */
+ snprintf(buf, sizeof(buf), "WiMAX %s", wmx->name);
+ result = genl_ctrl_resolve(wmx->nlh_tx, buf);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: device %s presents no WiMAX interface; "
+ "it might not exist, not be be a WiMAX device or "
+ "support an interface unknown to libwimax: %d\n",
+ wmx->name, result);
+ goto error_ctrl_resolve;
+ }
+ wmx->gnl_family_id = result;
+ d_printf(1, wmx, "D: WiMAX device %s, genl family ID %d\n",
+ wmx->name, wmx->gnl_family_id);
+
+ result = __wimaxll_cmd_open(wmx); /* Get interface information */
+ if (result < 0)
+ goto error_cmd_open;
+
+ result = wimaxll_mc_rx_open(wmx, "msg");
+ if (result == -EPROTONOSUPPORT) /* not open? */
+ wmx->mc_msg = WIMAXLL_MC_MAX; /* for wimaxll_mc_rx_read() */
+ else if (result < 0) {
+ wimaxll_msg(wmx, "E: cannot open 'msg' multicast group: "
+ "%d\n", result);
+ goto error_msg_open;
+ } else
+ wmx->mc_msg = result;
+ d_fnend(3, wmx, "(device %s) = %p\n", device, wmx);
+ return wmx;
+
+ wimaxll_mc_rx_close(wmx, wmx->mc_msg);
+error_msg_open:
+error_cmd_open:
+error_ctrl_resolve:
+ nl_close(wmx->nlh_tx);
+error_nl_connect_tx:
+ nl_handle_destroy(wmx->nlh_tx);
+error_nl_handle_alloc_tx:
+ wimaxll_free(wmx);
+error_gnl_handle_alloc:
+ errno = -result;
+ d_fnend(3, NULL, "(device %s) = NULL\n", device);
+ return NULL;
+}
+
+
+/**
+ * Close a device handle opened with wimaxll_open()
+ *
+ * \param wmx WiMAX device handle
+ *
+ * \ingroup device_management
+ * \internal
+ *
+ * Performs the natural oposite actions done in wimaxll_open(). All
+ * generic netlink multicast groups are destroyed, the netlink handle
+ * is closed and destroyed and finally, the actual handle is released.
+ */
+void wimaxll_close(struct wimaxll_handle *wmx)
+{
+ unsigned cnt;
+
+ d_fnstart(3, NULL, "(wmx %p)\n", wmx);
+ for (cnt = 0; cnt < WIMAXLL_MC_MAX; cnt++)
+ if (wmx->gnl_mc[cnt].mch)
+ wimaxll_mc_rx_close(wmx, cnt);
+ nl_close(wmx->nlh_tx);
+ nl_handle_destroy(wmx->nlh_tx);
+ wimaxll_free(wmx);
+ d_fnend(3, NULL, "(wmx %p) = void\n", wmx);
+}
+
+void wimax_open() __attribute__ ((weak, alias("wimaxll_open")));
+void wimax_close() __attribute__ ((weak, alias("wimaxll_close")));
diff --git a/lib/op-reset.c b/lib/op-reset.c
new file mode 100644
index 0000000..7f402fd
--- /dev/null
+++ b/lib/op-reset.c
@@ -0,0 +1,122 @@
+/*
+ * Linux WiMax
+ * Export the kernel's WiMAX stack wimaxll_reset() function
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+#include <linux/types.h>
+#include <netlink/msg.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <wimaxll.h>
+#include "internal.h"
+#define D_LOCAL 0
+#include "debug.h"
+
+
+/**
+ * Reset a WiMAX device
+ *
+ * \param wmx WiMAX device handle
+ *
+ * \return result of the operation.
+ *
+ * - 0: wam reset suceeded
+ * - -ENODEV: warm reset failed and had to resort to a cold/bus
+ * reset; the device was disconnected from the system and the
+ * current handle is invalid and should be closed.
+ * - Any other negative error code: unrecoverable error, shutdown
+ * and go home
+ *
+ * When there is a need to reset the device wimaxll_reset() can be used
+ * to issue a warm reset. That won't invalidate the existing handles,
+ * while still moving the device to power on state.
+ *
+ * If the device cannot be properly reset, the WiMAX kernel stack may
+ * fall back to a cold reset, which will most likely disconnect the
+ * device from the driver (and bus) and reconnect it; that means
+ * device handles will be invalid from there on. In those cases,
+ * -ENODEV is returned.
+ *
+ * \note This call is synchronous; when success is returned, the
+ * device has completed its internal reset.
+ *
+ * \ingroup device_management
+ * \internal
+ *
+ * This implementation simply marshalls the call to the kernel's
+ * wimax_reset() and returns it's return code.
+ */
+int wimaxll_reset(struct wimaxll_handle *wmx)
+{
+ ssize_t result;
+ struct nl_msg *msg;
+
+ msg = nlmsg_new();
+ if (msg == NULL) {
+ result = errno;
+ wimaxll_msg(wmx, "E: RESET: cannot allocate generic netlink "
+ "message: %m\n");
+ goto error_msg_alloc;
+ }
+ if (genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ,
+ wimaxll_family_id(wmx), 0, 0,
+ WIMAX_GNL_OP_RESET, WIMAX_GNL_VERSION) == NULL) {
+ result = -ENOMEM;
+ wimaxll_msg(wmx, "E: RESET: error preparing message: "
+ "%d 0x%08x\n", result, result);
+ goto error_msg_prep;
+ }
+ result = nl_send_auto_complete(wmx->nlh_tx, msg);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: RESET: error sending message: %zd\n",
+ result);
+ goto error_msg_send;
+ }
+ /* Read the message ACK from netlink */
+ result = wimaxll_wait_for_rp_result(wmx);
+ nl_wait_for_ack(wmx->nlh_tx);
+ if (result < 0)
+ wimaxll_msg(wmx, "E: RESET: operation failed: %zd\n", result);
+error_msg_prep:
+error_msg_send:
+ nlmsg_free(msg);
+error_msg_alloc:
+ return result;
+}
diff --git a/lib/op-rfkill.c b/lib/op-rfkill.c
new file mode 100644
index 0000000..a5695c9
--- /dev/null
+++ b/lib/op-rfkill.c
@@ -0,0 +1,129 @@
+/*
+ * Linux WiMax
+ * Export the kernel's WiMAX stack wimaxll_rfkill() function
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+#include <linux/types.h>
+#include <netlink/msg.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <wimaxll.h>
+#include "internal.h"
+#define D_LOCAL 0
+#include "debug.h"
+
+
+/**
+ * Control the software RF Kill switch and obtain switch status
+ *
+ * \param wmx WiMAX device handle
+ *
+ * \param state State to which you want to toggle the sofware RF Kill
+ * switch (%WIMAX_RF_ON, %WIMAX_RF_OFF or %WIMAX_RF_QUERY for just
+ * querying the current state of the hardware and software
+ * switches).
+ *
+ * \return Negative errno code on error. Otherwise, radio kill switch
+ * status (bit 0 \e hw switch, bit 1 \e sw switch, \e 0 OFF, \e 1
+ * ON):
+ * - 3 @c 0b11: Both HW and SW switches are \e on, radio is \e on
+ * - 2 @c 0b10: HW switch is \e off, radio is \e off
+ * - 1 @c 0b01: SW switch is \e on, radio is \e off
+ * - 0 @c 0b00: Both HW and SW switches are \e off, radio is \e off
+ *
+ * Allows the caller to control the state of the software RF Kill
+ * switch (if present) and in return, obtain the current status of
+ * both the hardware and software RF Kill switches.
+ *
+ * If there is no hardware or software switch, that switch is assumed
+ * to be always on (radio on).
+ *
+ * Changing the radio state might cause the device to change state,
+ * and cause the kernel to send reports indicating so.
+ *
+ * \note The state of the radio (\e ON or \e OFF) is the inverse of
+ * the state of the RF-Kill switch (\e enabled/on kills the
+ * radio, radio \e off; \e disabled/off allows the radio to
+ * work, radio \e on).
+ *
+ * \ingroup device_management
+ * \internal
+ *
+ * This implementation simply marshalls the call to the kernel's
+ * wimax_rfkill() and returns it's return code.
+ */
+int wimaxll_rfkill(struct wimaxll_handle *wmx, enum wimax_rf_state state)
+{
+ ssize_t result;
+ struct nl_msg *msg;
+
+ msg = nlmsg_new();
+ if (msg == NULL) {
+ result = errno;
+ wimaxll_msg(wmx, "E: RFKILL: cannot allocate generic netlink "
+ "message: %m\n");
+ goto error_msg_alloc;
+ }
+ if (genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ,
+ wimaxll_family_id(wmx), 0, 0,
+ WIMAX_GNL_OP_RFKILL, WIMAX_GNL_VERSION) == NULL) {
+ result = -ENOMEM;
+ wimaxll_msg(wmx, "E: RFKILL: error preparing message: "
+ "%d 0x%08x\n", result, result);
+ goto error_msg_prep;
+ }
+ nla_put_u32(msg, WIMAX_GNL_RFKILL_STATE, (__u32) state);
+ result = nl_send_auto_complete(wmx->nlh_tx, msg);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: RFKILL: error sending message: %zd\n",
+ result);
+ goto error_msg_send;
+ }
+ /* Read the message ACK from netlink */
+ result = wimaxll_wait_for_rp_result(wmx);
+ nl_wait_for_ack(wmx->nlh_tx);
+ if (result < 0)
+ wimaxll_msg(wmx, "E: RFKILL: operation failed: %zd\n", result);
+error_msg_prep:
+error_msg_send:
+ nlmsg_free(msg);
+error_msg_alloc:
+ return result;
+}
diff --git a/lib/pipe.c b/lib/pipe.c
new file mode 100644
index 0000000..0cc710a
--- /dev/null
+++ b/lib/pipe.c
@@ -0,0 +1,196 @@
+/*
+ * Linux WiMax
+ * Pipe implementation
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * \defgroup the_pipe_interface_group The pipe interface
+ *
+ * This is a collection of tools for managing access to the different
+ * pipes that a WiMAX kernel driver can export.
+ *
+ * There is always a default pipe, the \e message pipe, on which the
+ * kernel sends notifications (such as the <em> \ref state_change_group
+ * "state change" </em> notification) and \ref the_messaging_interface
+ * "driver-specific messages".
+ *
+ * The driver can create other pipes for sending messages out of band
+ * without clogging the default \e message pipe. This can be used, for
+ * example, for high bandwidth driver-specific diagnostics.
+ *
+ * This is a low level interface and other than wimaxll_pipe_read()
+ * for reading notifications from the kernel stack in a mainloop, a
+ * normal library user should not need to use much of it.
+ *
+ * It is implemented a very thin layer on top of the \ref mc_rx
+ * "multicast RX interface".
+ *
+ * \section usage Usage
+ *
+ * If a WiMAX driver exports a set of pipes (each one with a different
+ * name), a handle to it can be opened with:
+ *
+ * \code
+ * pipe_id = wimaxll_pipe_open(wmx, "pipename");
+ * \endcode
+ *
+ * likewise, to close said pipe:
+ *
+ * \code
+ * wimaxll_pipe_close(wmx, pipe_id);
+ * \endcode
+ *
+ * To obtain the file descriptor associated to an opened pipe so that
+ * it can be fed to select():
+ *
+ * \code
+ * fd = wimaxll_pipe_fd(wmx, pipe_id);
+ * \endcode
+ *
+ * and finally to read from said pipe and execute the callbacks
+ * associated to each different notification from the kernel
+ *
+ * \code
+ * wimaxll_pipe_read(wmx, pipe_id);
+ * \endcode
+ *
+ * The default \e message pipe is always open, and it's \e pipe_id can
+ * be obtained with wimaxll_msg_pipe_id().
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+#include <linux/types.h>
+#include <netlink/msg.h>
+#include <netlink/genl/genl.h>
+#include <wimaxll.h>
+#include "internal.h"
+#define D_LOCAL 0
+#include "debug.h"
+
+
+/**
+ * Open a handle to receive messages from a WiMAX pipe
+ *
+ * \param wmx WiMAX device handle
+ * \param pipe_name Name of the pipe to open
+ *
+ * \return If successful, a non-negative pipe handle number (\e {the
+ * pipe id}). In case of error, a negative errno code.
+ *
+ * Opens a handle to receive data from the given WiMAX named
+ * pipe. wimaxll_pipe_msg_read() can be used to listen for data sent by
+ * the kernel on the named pipe.
+ *
+ * Only one handle may be opened at the same time to each pipe.
+ *
+ * \ingroup the_pipe_interface_group
+ */
+int wimaxll_pipe_open(struct wimaxll_handle *wmx, const char *pipe_name)
+{
+ return wimaxll_mc_rx_open(wmx, pipe_name);
+}
+
+
+/**
+ * Return the file descriptor associated to a multicast group
+ *
+ * \param wmx WiMAX device handle
+ * \param pipe_id Pipe ID, as returned by wimaxll_pipe_open().
+ * \return file descriptor associated to the multicast group, that can
+ * be fed to functions like select().
+ *
+ * This allows to select() on the file descriptor, which will block
+ * until a message is available, that then can be read with
+ * wimaxll_pipe_read() or wimaxll_pipe_msg_read().
+ *
+ * \ingroup the_pipe_interface_group
+ */
+int wimaxll_pipe_fd(struct wimaxll_handle *wmx, unsigned pipe_id)
+{
+ return wimaxll_mc_rx_fd(wmx, pipe_id);
+}
+
+
+/**
+ * Read any kind of kernel messages from a pipe and execute callbacks
+ *
+ * \param wmx WiMAX device handle
+ * \param pipe_id Pipe to read from [as returned by wimaxll_pipe_open()].
+ * \return If successful, 0 and the callbacks to known notifications will
+ * be called. On error, a negative errno code:
+ *
+ * -%EINPROGRESS: no messages received
+ *
+ * When reading notifications from the kernel, any unknown type will
+ * be ignored.
+ *
+ * \note This is a blocking call.
+ *
+ * \ingroup the_pipe_interface_group
+ */
+ssize_t wimaxll_pipe_read(struct wimaxll_handle *wmx, unsigned pipe_id)
+{
+ ssize_t result = -EINPROGRESS;
+ d_fnstart(3, wmx, "(wmx %p pipe_id %u)\n", wmx, pipe_id);
+ while (result == -EINPROGRESS || result == -ENODATA)
+ result = wimaxll_mc_rx_read(wmx, pipe_id);
+ d_fnend(3, wmx, "(wmx %p pipe_id %u) = %zd\n", wmx, pipe_id, result);
+ return result;
+}
+
+
+/**
+ * Close an a connection to a WiMAX pipe
+ *
+ * @param wmx WiMAX device handle
+ * \param pipe_id Pipe to close [as returned by wimaxll_pipe_open()].
+ *
+ * Closes the connection to the given WiMAX pipe.
+ *
+ * \ingroup the_pipe_interface_group
+ */
+void wimaxll_pipe_close(struct wimaxll_handle *wmx, unsigned pipe_id)
+{
+ wimaxll_mc_rx_close(wmx, pipe_id);
+}
+
+
+void wimax_pipe_open() __attribute__ ((weak, alias("wimaxll_pipe_open")));
+void wimax_pipe_fd() __attribute__ ((weak, alias("wimaxll_pipe_fd")));
+void wimax_pipe_read() __attribute__ ((weak, alias("wimaxll_pipe_read")));
+void wimax_pipe_close() __attribute__ ((weak, alias("wimaxll_pipe_close")));
diff --git a/lib/re-state-change.c b/lib/re-state-change.c
new file mode 100644
index 0000000..e0d1229
--- /dev/null
+++ b/lib/re-state-change.c
@@ -0,0 +1,317 @@
+/*
+ * Linux WiMax
+ * State Change Report
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * \defgroup state_change_group Tracking state changes
+ *
+ * When the WiMAX devices change state, the kernel sends \e state \e
+ * change notification.
+ *
+ * An application can simply block a thread waiting for state changes
+ * using the following convenience function:
+ *
+ * @code
+ * result = wimaxll_wait_for_state_change(wmx, &old_state, &new_state);
+ * @endcode
+ *
+ * However, in most cases, applications will want to integrate into
+ * main loops and use the callback mechanism.
+ *
+ * For that, they just need to set a callback for the state change
+ * notification:
+ *
+ *
+ * @code
+ * wimaxll_set_cb_state_change(wmx, my_state_change_callback, context_pointer);
+ * @endcode
+ *
+ * and then wait for notifications to be available (see \ref receiving
+ * "receiving with select()"). When data is available and
+ * wimax_pipe_read() called to process them, the callback will be
+ * executed for each state change notification.
+ *
+ * Applications can query the current callback set for the state
+ * change notifications with wimaxll_get_cb_state_change().
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+#include <linux/types.h>
+#include <netlink/msg.h>
+#include <netlink/genl/genl.h>
+#include <wimaxll.h>
+#include "internal.h"
+#define D_LOCAL 0
+#include "debug.h"
+
+
+
+/**
+ * WIMAX_GNL_RE_STATE_CHANGE: policy specification
+ *
+ * \internal
+ *
+ * Authoritative reference for this is at the kernel code,
+ * drivers/net/wimax/stack.c.
+ */
+static
+struct nla_policy wimaxll_gnl_re_state_change_policy[WIMAX_GNL_ATTR_MAX + 1] = {
+ [WIMAX_GNL_STCH_STATE_OLD] = { .type = NLA_U8 },
+ [WIMAX_GNL_STCH_STATE_NEW] = { .type = NLA_U8 },
+};
+
+
+/**
+ * Callback to process an WIMAX_GNL_RE_STATE_CHANGE from the kernel
+ *
+ * \internal
+ *
+ * \param wmx WiMAX device handle
+ * \param mch WiMAX multicast group handle
+ * \param msg Pointer to netlink message
+ * \return \c enum nl_cb_action
+ *
+ * wimaxll_mc_rx_read() calls libnl's nl_recvmsgs() to receive messages;
+ * when a valid message is received, it goes into a loop that selects
+ * a callback to run for each type of message and it will call this
+ * function.
+ *
+ * This just expects a _RE_STATE_CHANGE message, whose payload is what
+ * has to be passed to the caller. We just extract the data and call
+ * the callback defined by the caller to wimaxll_mc_rx_read() (or
+ * wimaxll_pipe_read()).
+ */
+int wimaxll_gnl_handle_state_change(struct wimaxll_handle *wmx,
+ struct wimaxll_mc_handle *mch,
+ struct nl_msg *msg)
+{
+ ssize_t result;
+ struct nlmsghdr *nl_hdr;
+ struct genlmsghdr *gnl_hdr;
+ struct nlattr *tb[WIMAX_GNL_ATTR_MAX+1];
+ struct wimaxll_gnl_cb_context *ctx = mch->state_change_context;
+ enum wimax_st old_state, new_state;
+
+ d_fnstart(7, wmx, "(msg %p mch %p)\n", msg, mch);
+ nl_hdr = nlmsg_hdr(msg);
+ gnl_hdr = nlmsg_data(nl_hdr);
+
+ assert(gnl_hdr->cmd == WIMAX_GNL_RE_STATE_CHANGE);
+
+ /* Parse the attributes */
+ result = genlmsg_parse(nl_hdr, 0, tb, WIMAX_GNL_ATTR_MAX,
+ wimaxll_gnl_re_state_change_policy);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: %s: genlmsg_parse() failed: %d\n",
+ __func__, result);
+ wimaxll_cb_context_set_result(ctx, result);
+ result = NL_SKIP;
+ goto error_parse;
+ }
+ if (tb[WIMAX_GNL_STCH_STATE_OLD] == NULL) {
+ wimaxll_msg(wmx, "E: %s: cannot find STCH_STATE_OLD "
+ "attribute\n", __func__);
+ wimaxll_cb_context_set_result(ctx, -ENXIO);
+ result = NL_SKIP;
+ goto error_no_attrs;
+
+ }
+ old_state = nla_get_u8(tb[WIMAX_GNL_STCH_STATE_OLD]);
+
+ if (tb[WIMAX_GNL_STCH_STATE_NEW] == NULL) {
+ wimaxll_msg(wmx, "E: %s: cannot find STCH_STATE_NEW "
+ "attribute\n", __func__);
+ wimaxll_cb_context_set_result(ctx, -ENXIO);
+ result = NL_SKIP;
+ goto error_no_attrs;
+
+ }
+ new_state = nla_get_u8(tb[WIMAX_GNL_STCH_STATE_NEW]);
+
+ wimaxll_cb_context_set_result(ctx, 0);
+ d_printf(1, wmx, "D: CRX re_state_change old %u new %u\n",
+ old_state, new_state);
+ if (mch->state_change_cb(wmx, ctx, old_state, new_state) == -EBUSY)
+ result = NL_STOP;
+ else
+ result = NL_OK;
+error_no_attrs:
+error_parse:
+ d_fnend(7, wmx, "(msg %p ctx %p) = %zd\n", msg, ctx, result);
+ return result;
+}
+
+
+/*
+ * Context for the default callback we use in
+ * wimaxll_wait_for_state_change()
+ */
+struct wimaxll_state_change_context {
+ struct wimaxll_gnl_cb_context ctx;
+ enum wimax_st *old_state, *new_state;
+ int set:1;
+};
+
+
+/**
+ * Get the callback and priv pointer for a WIMAX_GNL_RE_STATE_CHANGE message
+ *
+ * \param wmx WiMAX handle.
+ * \param cb Where to store the current callback function.
+ * \param context Where to store the private data pointer passed to the
+ * callback.
+ *
+ * \ingroup state_change_group
+ */
+void wimaxll_get_cb_state_change(struct wimaxll_handle *wmx,
+ wimaxll_state_change_cb_f *cb,
+ struct wimaxll_gnl_cb_context **context)
+{
+ struct wimaxll_mc_handle *mch;
+ mch = __wimaxll_get_mc_handle(wmx, wmx->mc_msg);
+ if (mch != NULL) {
+ *cb = mch->state_change_cb;
+ *context = mch->state_change_context;
+ }
+}
+
+
+/**
+ * Set the callback and priv pointer for a WIMAX_GNL_RE_STATE_CHANGE message
+ *
+ * \param wmx WiMAX handle.
+ * \param cb Callback function to set
+ * \param context Private data pointer to pass to the callback function.
+ *
+ * \ingroup state_change_group
+ */
+void wimaxll_set_cb_state_change(struct wimaxll_handle *wmx,
+ wimaxll_state_change_cb_f cb,
+ struct wimaxll_gnl_cb_context *context)
+{
+ struct wimaxll_mc_handle *mch;
+
+ mch = __wimaxll_get_mc_handle(wmx, wmx->mc_msg);
+ if (mch != NULL) {
+ mch->state_change_cb = cb;
+ mch->state_change_context = context;
+ }
+}
+
+
+/*
+ * Default callback we use in wimaxll_wait_for_state_change()
+ */
+static
+int wimaxll_cb_state_change(struct wimaxll_handle *wmx,
+ struct wimaxll_gnl_cb_context *ctx,
+ enum wimax_st old_state,
+ enum wimax_st new_state)
+{
+ struct wimaxll_state_change_context *stch_ctx =
+ wimaxll_container_of(ctx, struct wimaxll_state_change_context,
+ ctx);
+
+ if (stch_ctx->set)
+ return -EBUSY;
+ *stch_ctx->old_state = old_state;
+ *stch_ctx->new_state = new_state;
+ stch_ctx->set = 1;
+ return 0;
+}
+
+
+/**
+ * Wait for an state change notification from the kernel
+ *
+ * \param wmx WiMAX device handle
+ * \param old_state Pointer to where to store the previous state
+ * \param new_state Pointer to where to store the new state
+ * \return If successful, 0 and the values pointed to by the \a
+ * old_state and \a new_state arguments are valid; on error, a
+ * negative \a errno code and the state pointers contain no valid
+ * information.
+ *
+ * Waits for the WiMAX device to change state and reports said state
+ * change.
+ *
+ * Internally, this function uses wimax_pipe_read() on the default \e
+ * message pipe, which means that on reception (from the kernel) of
+ * notifications other than state change, any callbacks that are set
+ * for them will be executed.
+ *
+ * \note This is a blocking call.
+ *
+ * \note This function cannot be run in parallel with other code that
+ * modifies the \e state \e change callbacks for this same handle.
+ *
+ * \ingroup state_change_group
+ */
+ssize_t wimaxll_wait_for_state_change(struct wimaxll_handle *wmx,
+ enum wimax_st *old_state,
+ enum wimax_st *new_state)
+{
+ ssize_t result;
+ wimaxll_state_change_cb_f prev_cb = NULL;
+ struct wimaxll_gnl_cb_context *prev_ctx = NULL;
+ struct wimaxll_state_change_context ctx = {
+ .ctx = WIMAXLL_GNL_CB_CONTEXT_INIT(wmx),
+ .old_state = old_state,
+ .new_state = new_state,
+ .set = 0,
+ };
+
+ d_fnstart(3, wmx, "(wmx %p old_state %p new_state %p)\n",
+ wmx, old_state, new_state);
+ wimaxll_get_cb_state_change(wmx, &prev_cb, &prev_ctx);
+ wimaxll_set_cb_state_change(wmx, wimaxll_cb_state_change, &ctx.ctx);
+ result = wimaxll_pipe_read(wmx, wmx->mc_msg);
+ /* the callback filled out *old_state and *new_state if ok */
+ wimaxll_set_cb_state_change(wmx, prev_cb, prev_ctx);
+ d_fnend(3, wmx, "(wmx %p old_state %p [%u] new_state %p [%u])\n",
+ wmx, old_state, *old_state, new_state, *new_state);
+ return result;
+}
+
+void wimax_get_cb_state_change()
+ __attribute__ ((weak, alias("wimaxll_get_cb_state_change")));
+void wimax_set_cb_state_change()
+ __attribute__ ((weak, alias("wimaxll_set_cb_state_change")));
+void wimax_wait_for_state_change()
+ __attribute__ ((weak, alias("wimaxll_wait_for_state_change")));
diff --git a/lib/wimax.c b/lib/wimax.c
new file mode 100644
index 0000000..0f337fb
--- /dev/null
+++ b/lib/wimax.c
@@ -0,0 +1,443 @@
+/*
+ * Linux WiMax
+ * Shared/common routines
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * These are a set of facilities used by the implementation of the
+ * different ops in this library.
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+#include <linux/types.h>
+#include <netlink/msg.h>
+#include <netlink/genl/genl.h>
+#include <wimaxll.h>
+#include "internal.h"
+#define D_LOCAL 0
+#include "debug.h"
+
+
+/**
+ * Netlink callback to process netlink callback errors
+ *
+ * \internal
+ *
+ * \param nla Source netlink address
+ * \param nlerr Netlink error descritor
+ * \param _mch Pointer to (\a struct wimaxll_mc_handle)
+ *
+ * \return 'enum nl_cb_action', NL_OK if there is no error, NL_STOP on
+ * error and _mch->result possibly updated.
+ *
+ * While reading from netlink and processing with callbacks (using
+ * nl_recvmsgs()), we use this for the callback 'state machine' to
+ * store the result of an error message from the kernel.
+ */
+int wimaxll_gnl_error_cb(struct sockaddr_nl *nla, struct nlmsgerr *nlerr,
+ void *_mch)
+{
+ struct wimaxll_mc_handle *mch = _mch;
+ struct wimaxll_handle *wmx = mch->wmx;
+
+ d_fnstart(7, wmx, "(nla %p nlnerr %p [%d] mch %p)\n",
+ nla, nlerr, nlerr->error, _mch);
+ wimaxll_mch_maybe_set_result(mch, nlerr->error);
+ d_fnend(7, wmx, "(nla %p nlnerr %p [%d] mch %p) = %d\n",
+ nla, nlerr, nlerr->error, _mch, NL_STOP);
+ return NL_STOP;
+}
+
+
+/**
+ * Netlink callback to process an ack message and pass the 'error' code
+ *
+ * \internal
+ *
+ * Process a netlink ack message and extract the error code, which is
+ * placed in the context passed as argument for the calling function
+ * to use.
+ *
+ * We use this so that ACKers in the kernel can pass a simple error
+ * code (integer) in the ACK that netlink sends, without having to
+ * send an extra message.
+ *
+ * Complementary to wimaxll_gnl_error_cb().
+ *
+ * Frontend to this is wimaxll_wait_for_ack()
+ */
+static
+int wimaxll_gnl_ack_cb(struct nl_msg *msg, void *_mch)
+{
+ int result;
+ struct nlmsghdr *nl_hdr;
+ struct nlmsgerr *nl_err;
+ size_t size = nlmsg_len(nlmsg_hdr(msg));
+ struct wimaxll_mc_handle *mch = _mch;
+
+ nl_hdr = nlmsg_hdr(msg);
+ size = nlmsg_len(nl_hdr);
+ nl_err = nlmsg_data(nl_hdr);
+
+ if (size < sizeof(*nl_err)) {
+ wimaxll_msg(NULL, "E: netlink ack: buffer too small "
+ "(%zu vs %zu expected)\n",
+ size, sizeof(*nl_hdr) + sizeof(*nl_err));
+ result = -EIO;
+ goto error_ack_short;
+ }
+ d_printf(4, NULL, "netlink ack: nlmsghdr len %u type %u flags 0x%04x "
+ "seq 0x%x pid %u\n", nl_hdr->nlmsg_len, nl_hdr->nlmsg_type,
+ nl_hdr->nlmsg_flags, nl_hdr->nlmsg_seq, nl_hdr->nlmsg_pid);
+ if (nl_hdr->nlmsg_type != NLMSG_ERROR) {
+ wimaxll_msg(NULL, "E: netlink ack: message is not an ack but "
+ "type %u\n", nl_hdr->nlmsg_type);
+ result = -EBADE;
+ goto error_bad_type;
+ }
+ d_printf(4, NULL, "netlink ack: nlmsgerr error %d for "
+ "nlmsghdr len %u type %u flags 0x%04x seq 0x%x pid %u\n",
+ nl_err->error,
+ nl_err->msg.nlmsg_len, nl_err->msg.nlmsg_type,
+ nl_err->msg.nlmsg_flags, nl_err->msg.nlmsg_seq,
+ nl_err->msg.nlmsg_pid);
+ wimaxll_mch_maybe_set_result(mch, nl_err->error);
+ if (nl_err->error < 0)
+ d_printf(2, NULL, "D: netlink ack: received netlink error %d\n",
+ nl_err->error);
+error_ack_short:
+error_bad_type:
+ return NL_STOP;
+}
+
+
+/**
+ * Wait for a netlink ACK and pass on the result code it passed
+ *
+ * \internal
+ *
+ * \param wmx WiMAX device handle
+ * \return error code passed by the kernel in the nlmsgerr structure
+ * that contained the ACK.
+ *
+ * Similar to nl_wait_for_ack(), but returns the value in
+ * nlmsgerr->error, so it can be used by the kernel to return simple
+ * error codes.
+ */
+int wimaxll_wait_for_ack(struct wimaxll_handle *wmx)
+{
+ int result;
+ struct nl_cb *cb;
+ struct wimaxll_mc_handle fake_mch;
+
+ fake_mch.wmx = wmx;
+ fake_mch.result = -EINPROGRESS;
+
+ cb = nl_socket_get_cb(wmx->nlh_tx);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wimaxll_gnl_ack_cb, &fake_mch);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, NL_CB_DEFAULT, NULL);
+ nl_cb_err(cb, NL_CB_CUSTOM, wimaxll_gnl_error_cb, &fake_mch);
+ result = nl_recvmsgs_default(wmx->nlh_tx);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, NL_CB_DEFAULT, NULL);
+ nl_cb_put(cb);
+ if (result < 0)
+ return result;
+ return fake_mch.result;
+}
+
+
+/**
+ * WIMAX_GNL_RP_RESULT: policy specification
+ *
+ * \internal
+ *
+ * Authoritative reference for this is at the kernel code,
+ * drivers/net/wimax/stack.c.
+ */
+static
+struct nla_policy wimaxll_gnl_result_policy[WIMAX_GNL_ATTR_MAX + 1] = {
+ /* This is really a signed-64 bit number that has to be
+ * casted from a u64 */
+ [WIMAX_GNL_RESULT_CODE] = { .type = NLA_U64 },
+};
+
+
+/**
+ * Netlink callback to process a WIMAX_GNL_RP_RESULT message
+ *
+ * \internal
+ *
+ * \param msg Netlink message containing the reply
+ * \param _mch Pointer to a \a struct wimaxll_mc_handle where the
+ * result of the operation will be returned.
+ *
+ * \return 'enum nl_cb_action', NL_OK if there is no error, NL_STOP on
+ * error and _mch->result updated.
+ *
+ * This will take a received netlink message, check it is a \a
+ * WIMAX_GNL_RP_RESULT, parse the status code in it and store it the
+ * \m _mch's result data member for the caller to use later on.
+ */
+static
+int wimaxll_gnl_rp_result_cb(struct nl_msg *msg, void *_mch)
+{
+ int result;
+ struct wimaxll_mc_handle *mch = _mch;
+ struct wimaxll_handle *wmx = mch->wmx;
+ struct nlmsghdr *nl_hdr;
+ struct genlmsghdr *genl_hdr;
+ struct nlattr *tb[WIMAX_GNL_ATTR_MAX + 1];
+
+ d_fnstart(7, wmx, "(msg %p mch %p)\n", msg, _mch);
+ nl_hdr = nlmsg_hdr(msg);
+ genl_hdr = nlmsg_data(nl_hdr);
+
+ if (genl_hdr->cmd != WIMAX_GNL_RP_RESULT) {
+ result = NL_SKIP;
+ d_printf(1, wmx, "D: ignoring unknown command %d\n",
+ genl_hdr->cmd);
+ goto error_parse;
+ }
+
+ /* Parse the attributes */
+ result = genlmsg_parse(nl_hdr, 0, tb, WIMAX_GNL_ATTR_MAX,
+ wimaxll_gnl_result_policy);
+ if (result < 0) {
+ wimaxll_msg(wmx, "E: %s: genlmsg_parse() failed: %d\n",
+ __func__, result);
+ wimaxll_mch_maybe_set_result(mch, -ENXIO);
+ result = NL_SKIP;
+ goto error_parse;
+ }
+ if (tb[WIMAX_GNL_RESULT_CODE] == NULL) {
+ wimaxll_msg(wmx, "E: %s: No result code argument passed\n",
+ __func__);
+ wimaxll_mch_maybe_set_result(mch, -ENXIO);
+ result = NL_SKIP;
+ goto error_no_result_code;
+
+ }
+ result = (ssize_t) nla_get_u64(tb[WIMAX_GNL_RESULT_CODE]);
+ wimaxll_mch_maybe_set_result(mch, result);
+ result = NL_OK;
+error_no_result_code:
+error_parse:
+ d_fnend(7, wmx, "(msg %p mch %p) = %d\n", msg, _mch, result);
+ return result;
+}
+
+
+/**
+ * Wait for a WIMAX_GNL_RP_RESULT reply (and an ack) and report its code
+ *
+ * \internal
+ *
+ * Many ops we execute in the kernel return just a signed integer for
+ * status using a WIMAX_GNL_RP_RESULT command for reply before sending
+ * the ACK.
+ *
+ * This function simplifies waiting for that and getting the reply.
+ *
+ * You still need to wait for the ack in your function calling
+ * nl_wait_for_ack().
+ *
+ * \note We use the same handler used for transmission in the TX side
+ * and it's callback set, that we modifiy. As noted in the doc for
+ * \a struct wimaxll_handle, each call site to nl_recvmsgs_default()
+ * on \a wmx->nlh_tx must make sure the NL_CB_VALID and
+ * nl_cb_err() callbacks are properly set.
+ */
+ssize_t wimaxll_wait_for_rp_result(struct wimaxll_handle *wmx)
+{
+ ssize_t result;
+ struct nl_cb *cb;
+ struct wimaxll_mc_handle fake_mch;
+
+ d_fnstart(5, wmx, "(wmx %p)\n", wmx);
+ fake_mch.wmx = wmx;
+ fake_mch.result = -EINPROGRESS;
+ cb = nl_socket_get_cb(wmx->nlh_tx);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
+ wimaxll_gnl_rp_result_cb, &fake_mch);
+ nl_cb_err(cb, NL_CB_CUSTOM, wimaxll_gnl_error_cb, &fake_mch);
+ nl_recvmsgs_default(wmx->nlh_tx);
+ nl_cb_put(cb);
+
+ result = fake_mch.result;
+ if (result == -EINPROGRESS)
+ wimaxll_msg(wmx, "E: %s: the kernel didn't reply with a "
+ "WIMAX_GNL_RP_RESULT message\n", __func__);
+ else
+ d_printf(1, wmx, "D: WIMAX_GNL_RP_RESULT code is %d\n", result);
+ d_fnend(5, wmx, "(wmx %p) = %zd\n", wmx, result);
+ return result;
+}
+
+
+/**
+ * \defgroup diagnostics_group Output of diagnostics messages
+ *
+ * The \e libwimaxll library prints diagnostics by default to \a
+ * stderr. Said destination can be changed by the user by setting the
+ * wimaxll_vmsg() function pointer before calling any other \a
+ * libwimaxll function.
+ *
+ * To restore the default diagnostics destination, set wimaxll_vmsg()
+ * back to wimaxll_vmsg_stderr().
+ */
+
+
+/**
+ * Deliver \e libwimaxll diagnostics messages to \e stderr
+ *
+ * \param fmt printf-like format
+ * \param vargs variable-argument list as created by
+ * stdargs.h:va_list() that will be formatted according to \e
+ * fmt.
+ *
+ * Default diagnostics printing function.
+ *
+ * \ingroup diagnostics_group
+ */
+void wimaxll_vmsg_stderr(const char *fmt, va_list vargs)
+{
+ vfprintf(stderr, fmt, vargs);
+}
+
+
+
+/**
+ * Print library diagnostics messages [backend]
+ *
+ * @param fmt printf-like format
+ * @param vargs variable-argument list as created by
+ * stdargs.h:va_list() that will be formatted according to \e
+ * fmt.
+ *
+ * Prints/writes the \e libwimaxll's diagnostics messages to a
+ * destination as selected by the user of the library.
+ *
+ * \note This function pointer must be set \b before calling any other
+ * \e libwimaxll function.
+ *
+ * By default, diagnostics are printed with wimaxll_vmsg_stderr() to
+ * \a stderr.
+ *
+ * For example, to deliver diagnostics to syslog:
+ *
+ * @code
+ * #include <syslog.h>
+ * ...
+ * static
+ * void wimaxll_vmsg_syslog(const char *fmt, va_list vargs)
+ * {
+ * vsyslog(LOG_MAKEPRI(LOG_USER, LOG_INFO), fmt, vargs);
+ * }
+ * ...
+ * wimaxll_vmsg = wimaxll_vmsg_syslog();
+ * ...
+ * wimaxll_open(BLAH);
+ * @endcode
+ *
+ * \ingroup diagnostics_group
+ * \internal
+ *
+ * The internal function wimaxll_msg() is used as as a frontend to
+ * this function.
+ */
+void (*wimaxll_vmsg)(const char *fmt, va_list vargs) = wimaxll_vmsg_stderr;
+
+
+static
+void __wimaxll_msg(const char *fmt, ...)
+{
+ va_list vargs;
+ va_start(vargs, fmt);
+ wimaxll_vmsg(fmt, vargs);
+ va_end(vargs);
+}
+
+
+/**
+ * \internal
+ *
+ * Prints library diagnostic messages with a predefined format [frontend]
+ *
+ * @param wmx WiMAX handle; if NULL, no device header will be presented.
+ * @param fmt printf-like format followed by any arguments
+ *
+ * Called by the library functions to print status/error messages. By
+ * default these are sent over to stderr.
+ *
+ * However, library users can change this default behaviour by setting
+ * wimaxll_vmsg() as documented in that function pointer's
+ * documentation.
+ *
+ * \ingroup diagnostics_group
+ */
+void wimaxll_msg(struct wimaxll_handle *wmx, const char *fmt, ...)
+{
+ va_list vargs;
+ if (wmx == NULL)
+ __wimaxll_msg("libwimax: ");
+ else if ((unsigned long) wmx < 4096) {
+ __wimaxll_msg("libwimax: E: Corrupt device handle %p\n", wmx);
+ __wimaxll_msg("libwimax[n/a]: ");
+ } else
+ __wimaxll_msg("libwimax[%s]: ", wmx->name);
+ va_start(vargs, fmt);
+ wimaxll_vmsg(fmt, vargs);
+ va_end(vargs);
+}
+
+
+/**
+ * Return the name of a the system's WiMAX interface associated to an
+ * open handle
+ *
+ * \param wmx WiMAX device handle
+ * \return Interface name (only valid while the handle is open)
+ *
+ * \ingroup device_management
+ */
+const char *wimaxll_ifname(const struct wimaxll_handle *wmx)
+{
+ return wmx->name;
+}
+
+void wimax_ifname() __attribute__ ((weak, alias("wimaxll_ifname")));