summary refs log tree commit diff
path: root/src/devices/wimax
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2014-07-06 02:16:10 +0200
committerMichael Biebl <biebl@debian.org>2014-07-06 02:16:10 +0200
commit33491bc4279481db8ae47213e34a6d695a0e8830 (patch)
tree097d2b0fdff3fae6885381ae5e57a182cd8cbbba /src/devices/wimax
parent59c3714a494c3b3765657c0551ad82842d98a7d2 (diff)
Imported Upstream version 0.9.10.0 upstream/0.9.10.0
Diffstat (limited to 'src/devices/wimax')
-rw-r--r--src/devices/wimax/Makefile.am63
-rw-r--r--src/devices/wimax/Makefile.in850
-rw-r--r--src/devices/wimax/exports.ver7
-rw-r--r--src/devices/wimax/iwmxsdk.c1517
-rw-r--r--src/devices/wimax/iwmxsdk.h111
-rw-r--r--src/devices/wimax/nm-device-wimax.c1445
-rw-r--r--src/devices/wimax/nm-device-wimax.h73
-rw-r--r--src/devices/wimax/nm-wimax-factory.c89
-rw-r--r--src/devices/wimax/nm-wimax-nsp.c242
-rw-r--r--src/devices/wimax/nm-wimax-nsp.h63
-rw-r--r--src/devices/wimax/nm-wimax-types.h31
-rw-r--r--src/devices/wimax/nm-wimax-util.c82
-rw-r--r--src/devices/wimax/nm-wimax-util.h38
13 files changed, 4611 insertions, 0 deletions
diff --git a/src/devices/wimax/Makefile.am b/src/devices/wimax/Makefile.am
new file mode 100644
index 00000000..def8bf62
--- /dev/null
+++ b/src/devices/wimax/Makefile.am
@@ -0,0 +1,63 @@
+AM_CPPFLAGS = \
+	-I${top_srcdir}/src \
+	-I${top_builddir}/src \
+	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/devices \
+	-I${top_srcdir}/src/platform \
+	-I${top_builddir}/include \
+	-I${top_srcdir}/include \
+	-I${top_builddir}/libnm-util \
+	-I${top_srcdir}/libnm-util \
+	-DG_LOG_DOMAIN=\""NetworkManager-wimax"\" \
+	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+	$(DBUS_CFLAGS) \
+	$(POLKIT_CFLAGS) \
+	$(IWMX_SDK_CFLAGS) \
+	$(LIBNL_CFLAGS) \
+	$(GUDEV_CFLAGS)
+
+pkglib_LTLIBRARIES = libnm-device-plugin-wimax.la
+
+SYMBOL_VIS_FILE=$(srcdir)/exports.ver
+
+libnm_device_plugin_wimax_la_SOURCES = \
+	nm-wimax-factory.c \
+	nm-device-wimax.c \
+	nm-device-wimax.h \
+	nm-wimax-nsp.c \
+	nm-wimax-nsp.h \
+	nm-wimax-types.h \
+	nm-wimax-util.c \
+	nm-wimax-util.h \
+	iwmxsdk.c \
+	iwmxsdk.h
+
+libnm_device_plugin_wimax_la_LDFLAGS = \
+	-module -avoid-version \
+	-Wl,--version-script=$(SYMBOL_VIS_FILE)
+
+libnm_device_plugin_wimax_la_LIBADD = \
+	$(DBUS_LIBS) \
+	$(IWMX_SDK_LIBS) \
+	$(GUDEV_LIBS)
+
+nm-wimax-nsp-glue.h: $(top_srcdir)/introspection/nm-wimax-nsp.xml
+	dbus-binding-tool --prefix=nm_wimax_nsp --mode=glib-server --output=$@ $<
+
+nm-device-wimax-glue.h: $(top_srcdir)/introspection/nm-device-wimax.xml
+	dbus-binding-tool --prefix=nm_device_wimax --mode=glib-server --output=$@ $<
+
+BUILT_SOURCES = \
+	nm-wimax-nsp-glue.h \
+	nm-device-wimax-glue.h
+
+CLEANFILES = $(BUILT_SOURCES)
+EXTRA_DIST = $(SYMBOL_VIS_FILE)
+
+if ENABLE_TESTS
+
+check-local:
+	$(top_srcdir)/tools/check-exports.sh $(builddir)/.libs/libnm-device-plugin-wimax.so $(SYMBOL_VIS_FILE)
+
+endif
+
diff --git a/src/devices/wimax/Makefile.in b/src/devices/wimax/Makefile.in
new file mode 100644
index 00000000..ba16d277
--- /dev/null
+++ b/src/devices/wimax/Makefile.in
@@ -0,0 +1,850 @@
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 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@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@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 = src/devices/wimax
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+	$(top_srcdir)/build-aux/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
+	$(top_srcdir)/m4/compiler_warnings.m4 \
+	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gnome-code-coverage.m4 \
+	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
+	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
+	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
+	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_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 = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libnm_device_plugin_wimax_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libnm_device_plugin_wimax_la_OBJECTS = nm-wimax-factory.lo \
+	nm-device-wimax.lo nm-wimax-nsp.lo nm-wimax-util.lo iwmxsdk.lo
+libnm_device_plugin_wimax_la_OBJECTS =  \
+	$(am_libnm_device_plugin_wimax_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+libnm_device_plugin_wimax_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(AM_CFLAGS) $(CFLAGS) $(libnm_device_plugin_wimax_la_LDFLAGS) \
+	$(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libnm_device_plugin_wimax_la_SOURCES)
+DIST_SOURCES = $(libnm_device_plugin_wimax_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CKDB_PATH = @CKDB_PATH@
+CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
+DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
+DBUS_LIBS = @DBUS_LIBS@
+DBUS_SYS_DIR = @DBUS_SYS_DIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DHCLIENT_PATH = @DHCLIENT_PATH@
+DHCPCD_PATH = @DHCPCD_PATH@
+DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@
+DLLTOOL = @DLLTOOL@
+DNSMASQ_PATH = @DNSMASQ_PATH@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GENHTML = @GENHTML@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
+GNUTLS_LIBS = @GNUTLS_LIBS@
+GREP = @GREP@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
+INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
+INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
+INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
+INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
+INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
+INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
+INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
+IPTABLES_PATH = @IPTABLES_PATH@
+IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
+IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
+KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDL = @LIBDL@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBNDP_CFLAGS = @LIBNDP_CFLAGS@
+LIBNDP_LIBS = @LIBNDP_LIBS@
+LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_LIBS = @LIBNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTEAMDCTL_CFLAGS = @LIBTEAMDCTL_CFLAGS@
+LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MM_GLIB_CFLAGS = @MM_GLIB_CFLAGS@
+MM_GLIB_LIBS = @MM_GLIB_LIBS@
+MOC = @MOC@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NEWT_CFLAGS = @NEWT_CFLAGS@
+NEWT_LIBS = @NEWT_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
+NM_MICRO_VERSION = @NM_MICRO_VERSION@
+NM_MINOR_VERSION = @NM_MINOR_VERSION@
+NM_MODIFY_SYSTEM_POLICY = @NM_MODIFY_SYSTEM_POLICY@
+NM_VERSION = @NM_VERSION@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POLKIT_CFLAGS = @POLKIT_CFLAGS@
+POLKIT_LIBS = @POLKIT_LIBS@
+POSUB = @POSUB@
+PPPD_PATH = @PPPD_PATH@
+PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
+PPPOE_PATH = @PPPOE_PATH@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
+SED = @SED@
+SELINUX_CFLAGS = @SELINUX_CFLAGS@
+SELINUX_LIBS = @SELINUX_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SYSTEMD_200_CFLAGS = @SYSTEMD_200_CFLAGS@
+SYSTEMD_200_LIBS = @SYSTEMD_200_LIBS@
+SYSTEMD_INHIBIT_CFLAGS = @SYSTEMD_INHIBIT_CFLAGS@
+SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@
+SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@
+SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@
+SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
+UDEV_BASE_DIR = @UDEV_BASE_DIR@
+USE_NLS = @USE_NLS@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VALGRIND_RULES = @VALGRIND_RULES@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+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@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nmbinary = @nmbinary@
+nmconfdir = @nmconfdir@
+nmdatadir = @nmdatadir@
+nmrundir = @nmrundir@
+nmstatedir = @nmstatedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+systemdsystemunitdir = @systemdsystemunitdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+with_dhclient = @with_dhclient@
+with_dhcpcd = @with_dhcpcd@
+with_netconfig = @with_netconfig@
+with_resolvconf = @with_resolvconf@
+with_valgrind = @with_valgrind@
+AM_CPPFLAGS = \
+	-I${top_srcdir}/src \
+	-I${top_builddir}/src \
+	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/devices \
+	-I${top_srcdir}/src/platform \
+	-I${top_builddir}/include \
+	-I${top_srcdir}/include \
+	-I${top_builddir}/libnm-util \
+	-I${top_srcdir}/libnm-util \
+	-DG_LOG_DOMAIN=\""NetworkManager-wimax"\" \
+	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+	$(DBUS_CFLAGS) \
+	$(POLKIT_CFLAGS) \
+	$(IWMX_SDK_CFLAGS) \
+	$(LIBNL_CFLAGS) \
+	$(GUDEV_CFLAGS)
+
+pkglib_LTLIBRARIES = libnm-device-plugin-wimax.la
+SYMBOL_VIS_FILE = $(srcdir)/exports.ver
+libnm_device_plugin_wimax_la_SOURCES = \
+	nm-wimax-factory.c \
+	nm-device-wimax.c \
+	nm-device-wimax.h \
+	nm-wimax-nsp.c \
+	nm-wimax-nsp.h \
+	nm-wimax-types.h \
+	nm-wimax-util.c \
+	nm-wimax-util.h \
+	iwmxsdk.c \
+	iwmxsdk.h
+
+libnm_device_plugin_wimax_la_LDFLAGS = \
+	-module -avoid-version \
+	-Wl,--version-script=$(SYMBOL_VIS_FILE)
+
+libnm_device_plugin_wimax_la_LIBADD = \
+	$(DBUS_LIBS) \
+	$(IWMX_SDK_LIBS) \
+	$(GUDEV_LIBS)
+
+BUILT_SOURCES = \
+	nm-wimax-nsp-glue.h \
+	nm-device-wimax-glue.h
+
+CLEANFILES = $(BUILT_SOURCES)
+EXTRA_DIST = $(SYMBOL_VIS_FILE)
+all: $(BUILT_SOURCES)
+	$(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 ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/wimax/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu src/devices/wimax/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
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libnm-device-plugin-wimax.la: $(libnm_device_plugin_wimax_la_OBJECTS) $(libnm_device_plugin_wimax_la_DEPENDENCIES) $(EXTRA_libnm_device_plugin_wimax_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libnm_device_plugin_wimax_la_LINK) -rpath $(pkglibdir) $(libnm_device_plugin_wimax_la_OBJECTS) $(libnm_device_plugin_wimax_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iwmxsdk.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-wimax.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-wimax-factory.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-wimax-nsp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-wimax-util.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+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 "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+@ENABLE_TESTS_FALSE@check-local:
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) check-local
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) 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:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+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-pkglibLTLIBRARIES
+
+.MAKE: all check check-am install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am check-local clean \
+	clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	cscopelist-am ctags ctags-am distclean distclean-compile \
+	distclean-generic 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-html install-html-am \
+	install-info install-info-am install-man install-pdf \
+	install-pdf-am install-pkglibLTLIBRARIES 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 tags-am uninstall \
+	uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+nm-wimax-nsp-glue.h: $(top_srcdir)/introspection/nm-wimax-nsp.xml
+	dbus-binding-tool --prefix=nm_wimax_nsp --mode=glib-server --output=$@ $<
+
+nm-device-wimax-glue.h: $(top_srcdir)/introspection/nm-device-wimax.xml
+	dbus-binding-tool --prefix=nm_device_wimax --mode=glib-server --output=$@ $<
+
+@ENABLE_TESTS_TRUE@check-local:
+@ENABLE_TESTS_TRUE@	$(top_srcdir)/tools/check-exports.sh $(builddir)/.libs/libnm-device-plugin-wimax.so $(SYMBOL_VIS_FILE)
+
+# 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/src/devices/wimax/exports.ver b/src/devices/wimax/exports.ver
new file mode 100644
index 00000000..d2c45124
--- /dev/null
+++ b/src/devices/wimax/exports.ver
@@ -0,0 +1,7 @@
+{
+global:
+	nm_device_factory_create;
+	nm_device_factory_get_device_type;
+local:
+	*;
+};
diff --git a/src/devices/wimax/iwmxsdk.c b/src/devices/wimax/iwmxsdk.c
new file mode 100644
index 00000000..d1ef7b68
--- /dev/null
+++ b/src/devices/wimax/iwmxsdk.c
@@ -0,0 +1,1517 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ *
+ *  Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+ *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+
+#include <glib.h>
+
+#include <WiMaxType.h>
+#include <WiMaxAPI.h>
+#include <WiMaxAPIEx.h>
+
+#include "logging/nm-logging.h"
+#include "iwmxsdk.h"
+
+static WIMAX_API_DEVICE_ID g_api;
+static GMutex add_remove_mutex;
+
+/* Misc utilities */
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+/* Misc values */
+enum {
+	/*
+	 * WARNING!!!!!
+	 *
+	 * ONLY ONE DEVICE SUPPORTED
+	 *
+	 * - on removal, there is no way to know which device was
+	 *   removed (the removed device is removed from the list and
+	 *   the callback doesn't have any more information than the
+	 *   index in the list that getlistdevice would return -- racy
+	 *   as hell).
+	 *
+	 * - on insertion, there is not enough information provided.
+	 */
+	IWMX_SDK_DEV_MAX = 1,
+};
+
+/* Yes, this is dirty; see above on IWMX_SDK_DEV_MAX */
+static struct wmxsdk *g_iwmx_sdk_devs[IWMX_SDK_DEV_MAX];
+
+static struct wmxsdk *deviceid_to_wmxsdk(WIMAX_API_DEVICE_ID *device_id)
+{
+	unsigned cnt;
+	for (cnt = 0; cnt < IWMX_SDK_DEV_MAX; cnt++) {
+		struct wmxsdk *wmxsdk = g_iwmx_sdk_devs[cnt];
+		if (wmxsdk &&
+		    wmxsdk->device_id.deviceIndex == device_id->deviceIndex)
+			return wmxsdk;
+	}
+	return NULL;
+}
+
+static int deviceid_to_index(WIMAX_API_DEVICE_ID *device_id)
+{
+	unsigned cnt;
+
+	for (cnt = 0; cnt < IWMX_SDK_DEV_MAX; cnt++) {
+		struct wmxsdk *wmxsdk = g_iwmx_sdk_devs[cnt];
+		if (wmxsdk && wmxsdk->device_id.deviceIndex == device_id->deviceIndex)
+			return cnt;
+	}
+	return -1;
+}
+
+struct wmxsdk *iwmx_sdk_get_wmxsdk_for_iface(const char *iface)
+{
+	unsigned cnt;
+
+	for (cnt = 0; cnt < IWMX_SDK_DEV_MAX; cnt++) {
+		struct wmxsdk *wmxsdk = g_iwmx_sdk_devs[cnt];
+		if (wmxsdk && !strcmp(wmxsdk->ifname, iface))
+			return wmxsdk;
+	}
+	return NULL;
+}
+
+/*
+ * FIXME: pulled it it out of some hole
+ *
+ * the cinr to percentage computation comes from the L3/L4 doc
+ *
+ * But some other places (L4 code) have a more complex, seemingly
+ * logarithmical computation.
+ *
+ * Oh well...
+ *
+ */
+static int cinr_to_percentage(int cinr)
+{
+	int strength;
+	if (cinr <= -5)
+		strength = 0;
+	else if (cinr >= 25)
+		strength = 100;
+	else	/* Calc percentage on the value from -5 to 25 */
+		strength = ((100UL * (cinr - -5)) / (25 - -5));
+	return strength;
+}
+
+/**************************************************************/
+
+typedef struct {
+	WimaxNewWmxsdkFunc callback;
+	void *user_data;
+} NewSdkCallback;
+
+static GMutex new_callbacks_mutex;
+static GSList *new_callbacks = NULL;
+
+void iwmx_sdk_new_callback_register(WimaxNewWmxsdkFunc callback, void *user_data)
+{
+	NewSdkCallback *cb;
+
+	cb = g_malloc0 (sizeof (NewSdkCallback));
+	g_assert (cb);
+	cb->callback = callback;
+	cb->user_data = user_data;
+
+	g_mutex_lock (&new_callbacks_mutex);
+	new_callbacks = g_slist_append (new_callbacks, cb);
+	g_mutex_unlock (&new_callbacks_mutex);
+}
+
+void iwmx_sdk_new_callback_unregister(WimaxNewWmxsdkFunc callback, void *user_data)
+{
+	GSList *iter;
+	NewSdkCallback *found = NULL;
+
+	g_mutex_lock (&new_callbacks_mutex);
+	for (iter = new_callbacks; iter; iter = g_slist_next (iter)) {
+		NewSdkCallback *cb = iter->data;
+
+		if (cb->callback == callback && cb->user_data == user_data) {
+			found = cb;
+			break;
+		}
+	}
+
+	if (found) {
+		new_callbacks = g_slist_remove (new_callbacks, found);
+		g_free (found);
+	}
+	g_mutex_unlock (&new_callbacks_mutex);
+}
+
+static void iwmx_sdk_call_new_callbacks(struct wmxsdk *wmxsdk)
+{
+	GSList *iter;
+
+	g_mutex_lock (&new_callbacks_mutex);
+	for (iter = new_callbacks; iter; iter = g_slist_next (iter)) {
+		NewSdkCallback *cb = iter->data;
+
+		cb->callback (wmxsdk, cb->user_data);
+	}
+	g_mutex_unlock (&new_callbacks_mutex);
+}
+
+/****************************************************************/
+
+typedef struct {
+	struct wmxsdk *wmxsdk;
+	WIMAX_API_DEVICE_STATUS new_status;
+	WIMAX_API_DEVICE_STATUS old_status;
+	WIMAX_API_STATUS_REASON reason;
+	WIMAX_API_CONNECTION_PROGRESS_INFO progress;
+} StateChangeInfo;
+
+static gboolean
+state_change_handler(gpointer user_data)
+{
+	StateChangeInfo *info = user_data;
+
+	if (info->wmxsdk->state_change_cb) {
+		info->wmxsdk->state_change_cb(info->wmxsdk,
+		                              info->new_status,
+		                              info->old_status,
+		                              info->reason,
+		                              info->progress,
+		                              info->wmxsdk->callback_data);
+	}
+	wmxsdk_unref(info->wmxsdk);
+	memset(info, 0, sizeof(*info));
+	free(info);
+	return FALSE;
+}
+
+static void
+_schedule_state_change(struct wmxsdk *wmxsdk,
+                       WIMAX_API_DEVICE_STATUS new_status,
+                       WIMAX_API_DEVICE_STATUS old_status,
+                       WIMAX_API_STATUS_REASON reason,
+                       WIMAX_API_CONNECTION_PROGRESS_INFO progress)
+{
+	StateChangeInfo *info;
+
+	info = malloc(sizeof (*info));
+	if (!info)
+		return;
+
+	memset(info, 0, sizeof(*info));
+	info->wmxsdk = wmxsdk;
+	info->new_status = new_status;
+	info->old_status = old_status;
+	info->reason = reason;
+	info->progress = progress;
+
+	wmxsdk_ref(wmxsdk);
+	g_idle_add(state_change_handler, info);
+}
+
+typedef struct {
+	struct wmxsdk *wmxsdk;
+	WIMAX_API_MEDIA_STATUS media_status;
+} MediaStatusInfo;
+
+static gboolean
+media_status_change_handler(gpointer user_data)
+{
+	MediaStatusInfo *info = user_data;
+
+	if (info->wmxsdk->media_status_cb) {
+		info->wmxsdk->media_status_cb(info->wmxsdk,
+		                              info->media_status,
+		                              info->wmxsdk->callback_data);
+	}
+	wmxsdk_unref(info->wmxsdk);
+	memset(info, 0, sizeof(*info));
+	free(info);
+	return FALSE;
+}
+
+static void
+_schedule_media_status_change(struct wmxsdk *wmxsdk,
+                              WIMAX_API_MEDIA_STATUS media_status)
+{
+	MediaStatusInfo *info;
+
+	info = malloc(sizeof (*info));
+	if (!info)
+		return;
+
+	memset(info, 0, sizeof(*info));
+	info->wmxsdk = wmxsdk;
+	info->media_status = media_status;
+
+	wmxsdk_ref(wmxsdk);
+	g_idle_add(media_status_change_handler, info);
+}
+
+typedef struct {
+	struct wmxsdk *wmxsdk;
+	WIMAX_API_NETWORK_CONNECTION_RESP result;
+} ConnectResultInfo;
+
+static gboolean
+connect_result_handler(gpointer user_data)
+{
+	ConnectResultInfo *info = user_data;
+
+	if (info->wmxsdk->connect_result_cb) {
+		info->wmxsdk->connect_result_cb(info->wmxsdk,
+		                                info->result,
+		                                info->wmxsdk->callback_data);
+	}
+	wmxsdk_unref(info->wmxsdk);
+	memset(info, 0, sizeof(*info));
+	free(info);
+	return FALSE;
+}
+
+static void
+_schedule_connect_result(struct wmxsdk *wmxsdk,
+                         WIMAX_API_NETWORK_CONNECTION_RESP resp)
+{
+	ConnectResultInfo *info;
+
+	info = malloc(sizeof (*info));
+	if (!info)
+		return;
+
+	memset(info, 0, sizeof(*info));
+	info->wmxsdk = wmxsdk;
+	info->result = resp;
+
+	wmxsdk_ref(wmxsdk);
+	g_idle_add(connect_result_handler, info);
+}
+
+typedef struct {
+	struct wmxsdk *wmxsdk;
+	WIMAX_API_NSP_INFO_EX *nsps;
+	guint num_nsps;
+} ScanResultInfo;
+
+static gboolean
+scan_result_handler(gpointer user_data)
+{
+	ScanResultInfo *info = user_data;
+
+	if (info->wmxsdk->scan_result_cb) {
+		info->wmxsdk->scan_result_cb(info->wmxsdk,
+		                             info->nsps,
+		                             info->num_nsps,
+		                             info->wmxsdk->callback_data);
+	}
+	wmxsdk_unref(info->wmxsdk);
+	free(info->nsps);
+	memset(info, 0, sizeof(*info));
+	free(info);
+	return FALSE;
+}
+
+static void
+_schedule_scan_result(struct wmxsdk *wmxsdk,
+                      WIMAX_API_NSP_INFO_EX *nsps,
+                      guint num_nsps)
+{
+	ScanResultInfo *info;
+	size_t nsps_size;
+	int i, tmp;
+
+	info = malloc(sizeof (*info));
+	if (!info)
+		return;
+
+	memset(info, 0, sizeof(*info));
+	info->wmxsdk = wmxsdk;
+
+	nsps_size = num_nsps * sizeof (WIMAX_API_NSP_INFO_EX);
+	info->nsps = malloc(nsps_size);
+	memcpy(info->nsps, nsps, nsps_size);
+	info->num_nsps = num_nsps;
+
+	/* CAPI may report link quality as zero -- if it does check if it is a bug
+	 * by computing it based on CINR. If it is different, use the computed one.
+	 */
+	for (i = 0; i < num_nsps; i++) {
+		WIMAX_API_NSP_INFO_EX *nsp = &info->nsps[i];
+
+		if (nsp->linkQuality == 0) {
+			tmp = cinr_to_percentage(nsp->CINR - 10);
+			if (tmp != nsp->linkQuality)
+				nsp->linkQuality = tmp;
+		}
+	}
+
+	wmxsdk_ref(wmxsdk);
+	g_idle_add(scan_result_handler, info);
+}
+
+static gboolean
+removed_handler(gpointer user_data)
+{
+	struct wmxsdk *wmxsdk = user_data;
+
+	if (wmxsdk->removed_cb)
+		wmxsdk->removed_cb(wmxsdk, wmxsdk->callback_data);
+	wmxsdk_unref(wmxsdk);
+	return FALSE;
+}
+
+static void
+_schedule_removed(struct wmxsdk *wmxsdk)
+{
+	wmxsdk_ref(wmxsdk);
+	g_idle_add(removed_handler, wmxsdk);
+}
+
+/****************************************************************/
+
+/*
+ * Convert a WiMAX API status to an string.
+ */
+const char *iwmx_sdk_dev_status_to_str(WIMAX_API_DEVICE_STATUS status)
+{
+	switch (status) {
+	case WIMAX_API_DEVICE_STATUS_UnInitialized:
+		return "uninitialized";
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
+		return "rf off";
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
+		return "rf off (hard-block)";
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
+		return "rf off (soft-block)";
+	case WIMAX_API_DEVICE_STATUS_Ready:
+		return "ready";
+	case WIMAX_API_DEVICE_STATUS_Scanning:
+		return "scanning";
+	case WIMAX_API_DEVICE_STATUS_Connecting:
+		return "connecting";
+	case WIMAX_API_DEVICE_STATUS_Data_Connected:
+		return "connected";
+	default:
+		return "unknown";
+	}
+}
+
+const char *iwmx_sdk_reason_to_str(WIMAX_API_STATUS_REASON reason)
+{
+	switch (reason) {
+	case WIMAX_API_STATUS_REASON_Normal:
+		return "normal";
+
+	/**< Failed to complete NW entry with the selected operator (unspecified reason).  */
+	case WIMAX_API_STATUS_REASON_Fail_to_connect_to_NW:
+		return "unspecified failure";
+
+	/**< Failed to complete ranging */
+	case WIMAX_API_STATUS_REASON_Fail_to_connect_Ranging:
+		return "ranging failed";
+
+	/**< SBC phase failed */
+	case WIMAX_API_STATUS_REASON_Fail_to_connect_SBC:
+		return "sbc failed";
+
+	/**< Security error. EAP authentication failed device level */
+	case WIMAX_API_STATUS_REASON_Fail_to_connect_EAP_AUTH_Device:
+		return "EAP device auth failed";
+
+	/**< Security error. EAP authentication failed user level */
+	case WIMAX_API_STATUS_REASON_Fail_to_connect_EAP_AUTH_user:
+		return "EAP user auth failed";
+
+	/**< Security error. Handshake failed */
+	case WIMAX_API_STATUS_REASON_Fail_to_connect_3_Way_Handshake:
+		return "3 way handshake failed";
+
+	/**< Registration failed */
+	case WIMAX_API_STATUS_REASON_Fail_to_connect_REG:
+		return "registration failed";
+
+	/**< Failed to initialize the data path (failed to perform DSA to one UL and one DL SFs). */
+	case WIMAX_API_STATUS_REASON_Fail_to_connect_datapath:
+		return "datapath failed";
+
+	default:
+		return "unknown";
+	}
+}
+
+const char *iwmx_sdk_media_status_to_str(WIMAX_API_MEDIA_STATUS status)
+{
+	switch (status) {
+	case WIMAX_API_MEDIA_STATUS_LINK_UP:
+		return "link-up";
+	case WIMAX_API_MEDIA_STATUS_LINK_DOWN:
+		return "link-down";
+	case WIMAX_API_MEDIA_STATUS_LINK_RENEW:
+		return "link-renew";
+	default:
+		return "unknown";
+	}
+}
+
+const char *
+iwmx_sdk_con_progress_to_str(WIMAX_API_CONNECTION_PROGRESS_INFO progress)
+{
+	switch (progress) {
+
+	/**< Device is in Ranging */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_Ranging:
+		return "ranging";
+
+	/**< Device is in SBC */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_SBC:
+		return "sbc";
+
+	/**< Device is in EAP authentication Device */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_EAP_authentication_Device:
+		return "eap-auth-device";
+
+	/**< Device is in EAP authentication User */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_EAP_authentication_User:
+		return "eap-auth-user";
+
+	/**< Device is in 3-way-handshake */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_3_way_handshake:
+		return "3way-handshake";
+
+	/**< Device is in Registration */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_Registration:
+		return "registration";
+
+	/**< Device is in De-registration */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_De_registration:
+		return "deregistration";
+
+	/**< Device is registered (operational) */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_Registered:
+		return "registered";
+
+	default:
+		return "unknown";
+	}
+}
+
+/*
+ * Get the device's status from the device
+ *
+ * Does NOT cache the result
+ * Does NOT trigger a state change in NetworkManager
+ *
+ * Returns < 0 errno code on error, status code if ok.
+ */
+static WIMAX_API_DEVICE_STATUS iwmx_sdk_get_device_status(struct wmxsdk *wmxsdk)
+{
+	WIMAX_API_RET r;
+	char errstr[512];
+	UINT32 errstr_size = sizeof(errstr);
+
+	WIMAX_API_DEVICE_STATUS dev_status;
+	WIMAX_API_CONNECTION_PROGRESS_INFO pi;
+
+	r = GetDeviceStatus(&wmxsdk->device_id, &dev_status, &pi);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot read device state: %d (%s)", r, errstr);
+		dev_status = -EIO;
+	}
+	return dev_status;
+}
+
+/*
+ * Get the device's status from the device but return a string describing it
+ *
+ * Same conditions as iwmx_sdk_get_device_status().
+ */
+static const char *iwmx_sdk_get_device_status_str(struct wmxsdk *wmxsdk)
+{
+	const char *result;
+	WIMAX_API_DEVICE_STATUS dev_status;
+
+	dev_status = iwmx_sdk_get_device_status(wmxsdk);
+	if ((int) dev_status < 0)
+		result = "cannot read device state";
+	else
+		result = iwmx_sdk_dev_status_to_str(dev_status);
+	return result;
+}
+
+/*
+ * If the device is connected but we don't know about the network,
+ * create the knowledge of it.
+ *
+ * Asks the WiMAX API to report which NSP we are connected to and we
+ * create/update a network_el in the device's network list. Then
+ * return it.
+ *
+ * Returns NULL on error.
+ *
+ */
+WIMAX_API_CONNECTED_NSP_INFO_EX *iwmx_sdk_get_connected_network(struct wmxsdk *wmxsdk)
+{
+	WIMAX_API_CONNECTED_NSP_INFO_EX *nsp_info = NULL;
+	WIMAX_API_RET r;
+	char errstr[512];
+	UINT32 errstr_size = sizeof(errstr);
+
+	nsp_info = malloc(sizeof (*nsp_info));
+	if (!nsp_info) {
+		nm_log_err(LOGD_WIMAX, "wmxsdk: cannot allocate NSP info");
+		return NULL;
+	}
+
+	r = GetConnectedNSPEx(&wmxsdk->device_id, nsp_info);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot get connected NSP info: %d (%s)", r, errstr);
+		free (nsp_info);
+		nsp_info = NULL;
+	} else {
+		/* Migth be 0 sometimes; fix that up */
+		if (nsp_info->linkQuality == 0) {
+			int linkq_expected = cinr_to_percentage(nsp_info->CINR - 10);
+			if (linkq_expected != nsp_info->linkQuality)
+				nsp_info->linkQuality = linkq_expected;
+		}
+	}
+
+	return nsp_info;
+}
+
+/*
+ * Asks the WiMAX API to report current link statistics.
+ *
+ * Returns NULL on error.
+ *
+ */
+WIMAX_API_LINK_STATUS_INFO_EX *iwmx_sdk_get_link_status_info(struct wmxsdk *wmxsdk)
+{
+	WIMAX_API_LINK_STATUS_INFO_EX *stats = NULL;
+	WIMAX_API_RET r;
+	char errstr[512];
+	UINT32 errstr_size = sizeof(errstr);
+
+	/* Only report if connected */
+	if (iwmxsdk_status_get(wmxsdk) < WIMAX_API_DEVICE_STATUS_Connecting) {
+		nm_log_err(LOGD_WIMAX, "wmxsdk: cannot get link status info unless connected");
+		return NULL;
+	}
+
+	stats = malloc(sizeof (*stats));
+	if (!stats) {
+		nm_log_err(LOGD_WIMAX, "wmxsdk: cannot allocate links status info");
+		return NULL;
+	}
+
+	r = GetLinkStatusEx(&wmxsdk->device_id, stats);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot get link status info: %d (%s)", r, errstr);
+		free (stats);
+		stats = NULL;
+	}
+
+	return stats;
+}
+
+/*
+ * Callback for a RF State command
+ *
+ * Called by the WiMAX API when a command sent to change the RF state
+ * is completed. This is just a confirmation of what happened with the
+ * command.
+ *
+ * We don't do anything, as when the device changes state, the state
+ * change callback is called and that will fiddle with the NetworkManager
+ * internals.
+ */
+static void __iwmx_sdk_rf_state_cb(WIMAX_API_DEVICE_ID *device_id,
+				   WIMAX_API_RF_STATE rf_state)
+{
+	nm_log_dbg(LOGD_WIMAX, "rf_state changed to %d", rf_state);
+}
+
+/*
+ * Turn the radio on or off
+ *
+ * First it checks that we are in the right state before doing
+ * anything; there might be no need to do anything.
+ *
+ * Issue a command to the WiMAX API, wait for a callback confirming it
+ * is done. Sometimes the callback is missed -- in that case, do force
+ * a state change evaluation.
+ *
+ * Frustration note:
+ *
+ *      Geezoos efing Xist, they make difficult even the most simple
+ *      of the operations
+ *
+ *      This thing is definitely a pain. If the radio is ON already
+ *      and you switch it on again...well, there is no way to tell
+ *      because you don't get a callback saying it basically
+ *      suceeded. But on the other hand, if the thing was in a
+ *      different state and action needs to be taken, you have to wait
+ *      for a callback to confirm it's done. However, there is also an
+ *      state change callback, which is almost the same, so now you
+ *      have to handle things in two "unrelated" threads of execution.
+ *
+ *      How the shpx are you expected to tell the difference? Check
+ *      status first? On timeout? Nice gap (eighteen wheeler size) for
+ *      race conditions.
+ */
+int iwmx_sdk_rf_state_set(struct wmxsdk *wmxsdk, WIMAX_API_RF_STATE rf_state)
+{
+	int result;
+
+	WIMAX_API_RET r;
+	char errstr[512];
+	UINT32 errstr_size = sizeof(errstr);
+	WIMAX_API_DEVICE_STATUS dev_status;
+
+	g_assert(rf_state == WIMAX_API_RF_ON || rf_state == WIMAX_API_RF_OFF);
+
+	/* Guess what the current radio state is; if it is ON
+	 * already, don't redo it. */
+	dev_status = iwmx_sdk_get_device_status(wmxsdk);
+	if ((int) dev_status < 0) {
+		result = dev_status;
+		goto error_get_status;
+	}
+	switch (dev_status) {
+	case WIMAX_API_DEVICE_STATUS_UnInitialized:
+		result = -EINVAL;
+		goto error_cant_do;
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
+		nm_log_err(LOGD_WIMAX, "wmxsdk: cannot turn on radio: hw switch is off");
+		result = -EPERM;
+		goto error_cant_do;
+		break;
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
+		if (rf_state == WIMAX_API_RF_OFF) {
+			result = 0;
+			nm_log_dbg(LOGD_WIMAX, "radio is already off");
+			goto out_done;
+		}
+		break;
+	case WIMAX_API_DEVICE_STATUS_Ready:
+	case WIMAX_API_DEVICE_STATUS_Scanning:
+	case WIMAX_API_DEVICE_STATUS_Connecting:
+	case WIMAX_API_DEVICE_STATUS_Data_Connected:
+		if (rf_state == WIMAX_API_RF_ON) {
+			result = 0;
+			nm_log_dbg(LOGD_WIMAX, "radio is already on");
+			goto out_done;
+		}
+		break;
+	default:
+		g_assert(1);
+	}
+	/* Ok, flip the radio */
+	r = CmdControlPowerManagement(&wmxsdk->device_id, rf_state);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot flip radio to %d: %d (%s) [device is in state %s]",
+		           rf_state, r, errstr, iwmx_sdk_get_device_status_str(wmxsdk));
+		result = -EIO;
+	} else
+		result = -EINPROGRESS;
+out_done:
+error_cant_do:
+error_get_status:
+	return result;
+}
+
+/*
+ * Read the cached device status
+ */
+WIMAX_API_DEVICE_STATUS iwmxsdk_status_get(struct wmxsdk *wmxsdk)
+{
+	WIMAX_API_DEVICE_STATUS status;
+
+	g_mutex_lock(&wmxsdk->status_mutex);
+	status = wmxsdk->status;
+	g_mutex_unlock(&wmxsdk->status_mutex);
+	return status;
+}
+
+/*
+ * Callback for a Connect command
+ *
+ * Called by the WiMAX API when a command sent to connect is
+ * completed. This is just a confirmation of what happened with the
+ * command.
+ *
+ * WE DON'T DO MUCH HERE -- the real meat happens when a state change
+ * callback is sent, where we detect we move to connected state (or
+ * from disconnecting to something else); the state change callback is
+ * called and that will fiddle with the NetworkManager internals.
+ */
+static void __iwmx_sdk_connect_cb(WIMAX_API_DEVICE_ID *device_id,
+				  WIMAX_API_NETWORK_CONNECTION_RESP resp)
+{
+	WIMAX_API_DEVICE_STATUS status;
+	struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id);
+
+	status = iwmxsdk_status_get(wmxsdk);
+	if (resp == WIMAX_API_CONNECTION_SUCCESS) {
+		if (status != WIMAX_API_DEVICE_STATUS_Data_Connected) {
+			nm_log_err(LOGD_WIMAX, "wmxsdk: error: connect worked, but state"
+			           " didn't change (now it is %d [%s])",
+			           status,
+			           iwmx_sdk_dev_status_to_str(status));
+		}
+	} else {
+		nm_log_err(LOGD_WIMAX, "wmxsdk: failed to connect (status %d: %s)",
+		           status, iwmx_sdk_dev_status_to_str(status));
+	}
+
+	_schedule_connect_result(wmxsdk, resp);
+}
+
+/*
+ * Connect to a network
+ *
+ * This function starts the connection process to a given network;
+ * when the device changes status, the status change callback will
+ * tell NetworkManager if the network is finally connected or not.
+ *
+ * One of the reasons it is done like that is to allow external tools
+ * to control the device and the plugin just passing the status so
+ * NetworkManager displays the right info.
+ */
+int iwmx_sdk_connect(struct wmxsdk *wmxsdk, const char *nsp_name)
+{
+	int result = 0;
+
+	WIMAX_API_RET r;
+	char errstr[512];
+	UINT32 errstr_size = sizeof(errstr);
+	WIMAX_API_DEVICE_STATUS dev_status;
+	char sdk_name[MAX_SIZE_OF_NSP_NAME];
+
+	g_mutex_lock(&wmxsdk->connect_mutex);
+	/* Guess what the current radio state is; if it is ON
+	 * already, don't redo it. */
+	dev_status = iwmxsdk_status_get(wmxsdk);
+	if ((int) dev_status < 0) {
+		result = dev_status;
+		goto error_get_status;
+	}
+	switch (dev_status) {
+	case WIMAX_API_DEVICE_STATUS_UnInitialized:
+		nm_log_err(LOGD_WIMAX, "wmxsdk: SW BUG? HW is uninitialized");
+		result = -EINVAL;
+		goto error_cant_do;
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot connect: radio is off");
+		result = -EPERM;
+		goto error_cant_do;
+	case WIMAX_API_DEVICE_STATUS_Ready:
+	case WIMAX_API_DEVICE_STATUS_Scanning:
+		break;
+	case WIMAX_API_DEVICE_STATUS_Connecting:
+		nm_log_dbg(LOGD_WIMAX, "Connect already pending, waiting for it");
+		result = -EINPROGRESS;
+		goto error_cant_do;
+	case WIMAX_API_DEVICE_STATUS_Data_Connected:
+		nm_log_err(LOGD_WIMAX, "wmxsdk: BUG? need to disconnect?");
+		result = -EINVAL;
+		goto error_cant_do;
+	default:
+		g_assert(1);
+	}
+
+	/* The SDK treats the network name as wchar_t* while the contents are
+	 * actually just UTF-8...  WTF?  Hand it a full buffer to work around
+	 * boundary cases where the NSP name contains an odd # of characters.
+	 */
+	memset(sdk_name, 0, sizeof (sdk_name));
+	memcpy(sdk_name, nsp_name, strlen (nsp_name));
+
+	/* Ok, do the connection, wait for a callback */
+	r = CmdConnectToNetwork(&wmxsdk->device_id, &sdk_name[0], 0, 0);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot connect to network %s: %d (%s) - device is in state '%s'",
+		           nsp_name, r, errstr,
+		           iwmx_sdk_get_device_status_str(wmxsdk));
+		result = -EIO;
+	}
+
+error_cant_do:
+error_get_status:
+	g_mutex_unlock(&wmxsdk->connect_mutex);
+	return result;
+}
+
+/*
+ * Callback for a Disconnect command
+ *
+ * Called by the WiMAX API when a command sent to connect is
+ * completed. This is just a confirmation of what happened with the
+ * command.
+ *
+ * When the device changes state, the state change callback is called
+ * and that will fiddle with the NetworkManager internals.
+ *
+ * We just update the result of the command and wake up anybody who is
+ * waiting for this conditional variable.
+ */
+static void __iwmx_sdk_disconnect_cb(WIMAX_API_DEVICE_ID *device_id,
+				     WIMAX_API_NETWORK_CONNECTION_RESP resp)
+{
+	struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id);
+	WIMAX_API_DEVICE_STATUS status;
+
+	status = iwmxsdk_status_get(wmxsdk);
+	if (resp == WIMAX_API_CONNECTION_SUCCESS) {
+		if (status == WIMAX_API_DEVICE_STATUS_Data_Connected) {
+			nm_log_err(LOGD_WIMAX, "wmxsdk: error: disconnect worked, "
+				      "but state didn't change (now it is %d [%s])", status,
+				      iwmx_sdk_dev_status_to_str(status));
+		}
+	} else
+		nm_log_err(LOGD_WIMAX, "wmxsdk: failed to disconnect (status %d: %s)",
+			      status, iwmx_sdk_dev_status_to_str(status));
+}
+
+/*
+ * Disconnect from a network
+ *
+ * This function tells the device to disconnect; the state change
+ * callback will take care of inform NetworkManager's internals.
+ */
+int iwmx_sdk_disconnect(struct wmxsdk *wmxsdk)
+{
+	int result;
+
+	WIMAX_API_RET r;
+	char errstr[512];
+	UINT32 errstr_size = sizeof(errstr);
+	WIMAX_API_DEVICE_STATUS dev_status;
+
+	g_mutex_lock(&wmxsdk->connect_mutex);
+	/* Guess what the current radio state is; if it is ON
+	 * already, don't redo it. */
+	dev_status = iwmx_sdk_get_device_status(wmxsdk);
+	if ((int) dev_status < 0) {
+		result = dev_status;
+		goto error_get_status;
+	}
+	switch (dev_status) {
+	case WIMAX_API_DEVICE_STATUS_UnInitialized:
+		nm_log_err(LOGD_WIMAX, "wmxsdk: SW BUG? HW is uninitialized");
+		result = -EINVAL;
+		goto error_cant_do;
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
+		nm_log_dbg(LOGD_WIMAX, "Cannot disconnect, radio is off; ignoring");
+		result = 0;
+		goto error_cant_do;
+	case WIMAX_API_DEVICE_STATUS_Ready:
+	case WIMAX_API_DEVICE_STATUS_Scanning:
+		nm_log_dbg(LOGD_WIMAX, "Cannot disconnect, already disconnected; ignoring");
+		result = 0;
+		goto error_cant_do;
+	case WIMAX_API_DEVICE_STATUS_Connecting:
+	case WIMAX_API_DEVICE_STATUS_Data_Connected:
+		break;
+	default:
+		g_assert(1);
+	}
+	/* Ok, flip the radio */
+	r = CmdDisconnectFromNetwork(&wmxsdk->device_id);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot disconnect from network: %d (%s)", r, errstr);
+		result = -EIO;
+	} else
+		result = -EINPROGRESS;
+error_cant_do:
+error_get_status:
+	g_mutex_unlock(&wmxsdk->connect_mutex);
+	return result;
+}
+
+/*
+ * Turn fast reconnect capability on/off
+ *
+ * This function tells wimaxd to turn fast reconnect on or off.
+ */
+int iwmx_sdk_set_fast_reconnect_enabled(struct wmxsdk *wmxsdk, int enabled)
+{
+	WIMAX_API_RET r;
+	char errstr[512];
+	UINT32 errstr_size = sizeof(errstr);
+
+	r = SetFastReconnectCapabilityStatus(&wmxsdk->device_id, !!enabled);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot set fast reconnect to %d: %d (%s)",
+		           enabled, r, errstr);
+		return -EIO;
+	}
+	return 0;
+}
+
+static void __iwmx_sdk_media_status_update_cb (WIMAX_API_DEVICE_ID_P device_id,
+					WIMAX_API_MEDIA_STATUS mediaStatus)
+{
+	struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id);
+
+	/* Ignore redundant LINK_UP events */
+	if (   mediaStatus == WIMAX_API_MEDIA_STATUS_LINK_UP
+	    && wmxsdk->media_status == WIMAX_API_MEDIA_STATUS_LINK_UP)
+	    return;
+
+	wmxsdk->media_status = mediaStatus;
+
+	nm_log_dbg(LOGD_WIMAX, "wmxsdk: media status change to (%d) %s",
+	           mediaStatus, iwmx_sdk_media_status_to_str (mediaStatus));
+
+	_schedule_media_status_change(wmxsdk, mediaStatus);
+}
+
+/*
+ * Callback for state change messages
+ *
+ * Just pass them to the state transition handler
+ */
+static void __iwmx_sdk_state_change_cb(WIMAX_API_DEVICE_ID *device_id,
+					WIMAX_API_DEVICE_STATUS status,
+					WIMAX_API_STATUS_REASON reason,
+					WIMAX_API_CONNECTION_PROGRESS_INFO pi)
+{
+	struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id);
+	WIMAX_API_DEVICE_STATUS old_status;
+
+	nm_log_dbg(LOGD_WIMAX, "wmxsdk: state change to (%d) %s reason (%d) %s",
+	           status, iwmx_sdk_dev_status_to_str (status),
+	           reason, iwmx_sdk_reason_to_str (reason));
+
+	g_mutex_lock(&wmxsdk->status_mutex);
+	old_status = wmxsdk->status;
+	wmxsdk->status = status;
+	g_mutex_unlock(&wmxsdk->status_mutex);
+
+	_schedule_state_change(wmxsdk, status, old_status, reason, pi);
+}
+
+/*
+ * Called by _iwmx_sdk_*scan_cb() when [wide or preferred] scan results
+ * are available.
+ *
+ * From here we update NetworkManager's idea of which networks are available.
+ */
+static void __iwmx_sdk_scan_common_cb(WIMAX_API_DEVICE_ID *device_id,
+				      WIMAX_API_NSP_INFO_EX *nsp_list,
+				      UINT32 nsp_list_size)
+{
+	struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id);
+
+	g_mutex_lock(&wmxsdk->network_mutex);
+	_schedule_scan_result(wmxsdk, nsp_list, nsp_list_size);
+	g_mutex_unlock(&wmxsdk->network_mutex);
+}
+
+/*
+ * Called by the WiMAX API when we get a wide scan result
+ *
+ * We treat them same as wide, so we just call that.
+ */
+static void __iwmx_sdk_wide_scan_cb(WIMAX_API_DEVICE_ID *device_id,
+				    WIMAX_API_NSP_INFO_EX *nsp_list,
+				    UINT32 nsp_list_size)
+{
+	__iwmx_sdk_scan_common_cb(device_id, nsp_list, nsp_list_size);
+}
+
+/*
+ * Called by the WiMAX API when we get a normal (non wide) scan result
+ *
+ * We treat them same as wide, so we just call that.
+ */
+static void __iwmx_sdk_scan_cb(WIMAX_API_DEVICE_ID *device_id,
+				WIMAX_API_NSP_INFO_EX *nsp_list,
+				UINT32 nsp_list_size, UINT32 searchProgress)
+{
+	__iwmx_sdk_scan_common_cb(device_id, nsp_list, nsp_list_size);
+}
+
+/*
+ * Called to ask the device to scan for networks
+ *
+ * We don't really scan as the WiMAX SDK daemon scans in the
+ * background for us. We just get the results and hand them back via
+ * the scan_result_cb callback.
+ */
+int iwmx_sdk_get_networks(struct wmxsdk *wmxsdk)
+{
+	int result;
+
+	UINT32 nsp_list_length = 10;
+	WIMAX_API_NSP_INFO_EX nsp_list[10];	/* FIXME: up to 32? */
+
+	WIMAX_API_RET r;
+	char errstr[512];
+	UINT32 errstr_size = sizeof(errstr);
+
+	r = GetNetworkListEx(&wmxsdk->device_id, nsp_list, &nsp_list_length);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot get network list: %d (%s)", r, errstr);
+		result = -EIO;
+		goto error_scan;
+	}
+
+	if (nsp_list_length == 0) {
+		nm_log_dbg(LOGD_WIMAX, "no networks");
+	} else
+		__iwmx_sdk_scan_common_cb(&wmxsdk->device_id, nsp_list,
+					nsp_list_length);
+	result = 0;
+error_scan:
+	return result;
+}
+
+/*
+ * Initialize the WiMAX API, register with it, setup callbacks
+ *
+ */
+static int iwmx_sdk_setup(struct wmxsdk *wmxsdk)
+{
+	int result, status;
+
+	WIMAX_API_RET r;
+
+	char errstr[512];
+	UINT32 errstr_size = sizeof(errstr);
+
+	result = -ENFILE;
+
+	/* device_id initialized by iwmx_sdk_dev_add */
+
+	r = WiMaxDeviceOpen(&wmxsdk->device_id);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot open device: %d (%s)", r, errstr);
+		goto error_wimaxdeviceopen;
+	}
+
+	/*
+	 * We scan in auto mode (in the background)
+	 *
+	 * Otherwise is messy -- if we have NetworkManager triggering a scan
+	 * when we call iwmx_nm_scan() -> iwmx_sdk_scan(), most of the
+	 * times that causes a race condition when the UI asks for a
+	 * scan right before displaying the network menu. As there is
+	 * no way to cancel an ongoing scan before connecting, we are
+	 * stuck. So we do auto bg and have iwmx_sdk_scan() just return
+	 * the current network list.
+	 */
+	r = SetConnectionMode(&wmxsdk->device_id,
+			      WIMAX_API_CONNECTION_AUTO_SCAN_MANUAL_CONNECT);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot set connectin mode to manual: %d (%s)", r, errstr);
+		goto error_connection_mode;
+	}
+
+	r = SubscribeControlPowerManagement(&wmxsdk->device_id,
+					    __iwmx_sdk_rf_state_cb);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot subscribe to radio change events: %u (%s)", r, errstr);
+		result = -EIO;
+		goto error_subscribe_rf_state;
+	}
+
+	r = SubscribeDeviceStatusChange(&wmxsdk->device_id,
+					__iwmx_sdk_state_change_cb);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot subscribe to state chaneg events: %d (%s)", r, errstr);
+		goto error_subscribe_state_change;
+	}
+
+	r = SubscribeNetworkSearchWideScanEx(&wmxsdk->device_id,
+					     __iwmx_sdk_wide_scan_cb);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot subscribe to wide scan events: %d (%s)", r, errstr);
+		goto error_subscribe_wide_scan;
+	}
+	r = SubscribeNetworkSearchEx(&wmxsdk->device_id, __iwmx_sdk_scan_cb);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot subscribe to scan events: %d (%s)", r, errstr);
+		goto error_subscribe_scan;
+	}
+
+	r = SubscribeConnectToNetwork(&wmxsdk->device_id,
+				      __iwmx_sdk_connect_cb);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot subscribe to connect events: %d (%s)", r, errstr);
+		goto error_subscribe_connect;
+	}
+
+	r = SubscribeDisconnectToNetwork(&wmxsdk->device_id,
+					 __iwmx_sdk_disconnect_cb);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot subscribe to disconnect events: %d (%s)", r, errstr);
+		goto error_subscribe_disconnect;
+	}
+
+	r = SubscribeMediaStatusUpdate(&wmxsdk->device_id, __iwmx_sdk_media_status_update_cb);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot subscribe to media status events: %d (%s)", r, errstr);
+		goto error_subscribe_media_status;
+	}
+
+	status = iwmx_sdk_get_device_status(wmxsdk);
+	if ((int) status < 0)
+		status = WIMAX_API_DEVICE_STATUS_UnInitialized;
+
+	g_mutex_lock(&wmxsdk->status_mutex);
+	wmxsdk->status = status;
+	g_mutex_unlock(&wmxsdk->status_mutex);
+
+	_schedule_state_change(wmxsdk,
+	                       status,
+	                       WIMAX_API_DEVICE_STATUS_UnInitialized,
+	                       WIMAX_API_STATUS_REASON_Normal,
+	                       WIMAX_API_DEVICE_CONNECTION_PROGRESS_Ranging);
+
+	return 0;
+
+	UnsubscribeMediaStatusUpdate(&wmxsdk->device_id);
+error_subscribe_media_status:
+	UnsubscribeDisconnectToNetwork(&wmxsdk->device_id);
+error_subscribe_disconnect:
+	UnsubscribeConnectToNetwork(&wmxsdk->device_id);
+error_subscribe_connect:
+	UnsubscribeNetworkSearchEx(&wmxsdk->device_id);
+error_subscribe_scan:
+	UnsubscribeNetworkSearchWideScanEx(&wmxsdk->device_id);
+error_subscribe_wide_scan:
+	UnsubscribeDeviceStatusChange(&wmxsdk->device_id);
+error_subscribe_state_change:
+	UnsubscribeControlPowerManagement(&wmxsdk->device_id);
+error_subscribe_rf_state:
+error_connection_mode:
+	WiMaxDeviceClose(&wmxsdk->device_id);
+error_wimaxdeviceopen:
+	return result;
+}
+
+/*
+ * Called when a device is torn down
+ *
+ * Cleanup all that is done in iwmx_sdk_setup(). Remove callbacks,
+ * unregister from the WiMAX API.
+ */
+static void iwmx_sdk_remove(struct wmxsdk *wmxsdk)
+{
+	UnsubscribeMediaStatusUpdate(&wmxsdk->device_id);
+	UnsubscribeDisconnectToNetwork(&wmxsdk->device_id);
+	UnsubscribeConnectToNetwork(&wmxsdk->device_id);
+	UnsubscribeNetworkSearchEx(&wmxsdk->device_id);
+	UnsubscribeNetworkSearchWideScanEx(&wmxsdk->device_id);
+	UnsubscribeDeviceStatusChange(&wmxsdk->device_id);
+	UnsubscribeControlPowerManagement(&wmxsdk->device_id);
+	WiMaxDeviceClose(&wmxsdk->device_id);
+}
+
+void iwmx_sdk_set_callbacks(struct wmxsdk *wmxsdk,
+                            WimaxStateChangeFunc state_change_cb,
+                            WimaxMediaStatusFunc media_status_cb,
+                            WimaxConnectResultFunc connect_result_cb,
+                            WimaxScanResultFunc scan_result_cb,
+                            WimaxRemovedFunc removed_cb,
+                            void *user_data)
+{
+	wmxsdk->state_change_cb = state_change_cb;
+	wmxsdk->media_status_cb = media_status_cb;
+	wmxsdk->connect_result_cb = connect_result_cb;
+	wmxsdk->scan_result_cb = scan_result_cb;
+	wmxsdk->removed_cb = removed_cb;
+	wmxsdk->callback_data = user_data;
+}
+
+/* Initialize a [zeroed] struct wmxsdk */
+static struct wmxsdk *wmxsdk_new(void)
+{
+	struct wmxsdk *wmxsdk;
+
+	wmxsdk = malloc(sizeof(*wmxsdk));
+	if (wmxsdk) {
+		memset(wmxsdk, 0, sizeof(*wmxsdk));
+
+		wmxsdk->refcount = 1;
+		g_mutex_init(&wmxsdk->network_mutex);
+
+		wmxsdk->status = WIMAX_API_DEVICE_STATUS_UnInitialized;
+		g_mutex_init(&wmxsdk->status_mutex);
+
+		g_mutex_init(&wmxsdk->connect_mutex);
+	}
+	return wmxsdk;
+}
+
+struct wmxsdk *wmxsdk_ref(struct wmxsdk *wmxsdk)
+{
+	g_atomic_int_add(&wmxsdk->refcount, 1);
+	return wmxsdk;
+}
+
+void wmxsdk_unref(struct wmxsdk *wmxsdk)
+{
+	if (g_atomic_int_dec_and_test(&wmxsdk->refcount)) {
+		g_mutex_clear(&wmxsdk->status_mutex);
+		g_mutex_clear(&wmxsdk->connect_mutex);
+		memset(wmxsdk, 0, sizeof(*wmxsdk));
+		free(wmxsdk);
+	}
+}
+
+static void iwmx_sdk_dev_add(unsigned idx, unsigned api_idx, const char *name)
+{
+	struct wmxsdk *wmxsdk;
+	const char *s;
+
+	if (idx >= IWMX_SDK_DEV_MAX) {
+		nm_log_err(LOGD_WIMAX, "BUG! idx (%u) >= IWMX_SDK_DEV_MAX (%u)", idx, IWMX_SDK_DEV_MAX);
+		return;
+	}
+	if (g_iwmx_sdk_devs[idx] != NULL) {
+		nm_log_err(LOGD_WIMAX, "BUG! device index %u already enumerated?", idx);
+		return;
+	}
+
+	wmxsdk = wmxsdk_new();
+	if (wmxsdk == NULL) {
+		nm_log_err(LOGD_WIMAX, "Can't allocate %zu bytes", sizeof(*wmxsdk));
+		return;
+	}
+
+	/*
+	 * This depends on a hack in the WiMAX Network Service; it has
+	 * to return, as part of the device name, a string "if:IFNAME"
+	 * where the OS's device name is stored.
+	 */
+	s = strstr(name, "if:");
+	if (s == NULL
+	    || sscanf(s, "if:%15[^ \f\n\r\t\v]", wmxsdk->ifname) != 1) {
+		nm_log_err(LOGD_WIMAX, "Cannot extract network interface name off '%s'",
+			      name);
+		goto error;
+	}
+	nm_log_dbg(LOGD_WIMAX, "network interface name: '%s'", wmxsdk->ifname);
+
+	strncpy(wmxsdk->name, name, sizeof(wmxsdk->name));
+	wmxsdk->device_id.privilege = WIMAX_API_PRIVILEGE_READ_WRITE;
+	wmxsdk->device_id.deviceIndex = api_idx;
+
+	if (iwmx_sdk_setup(wmxsdk) != 0) {
+		nm_log_err(LOGD_WIMAX, "wxmsdk: %s: cannot set up interface", wmxsdk->ifname);
+		goto error;
+	}
+
+	g_iwmx_sdk_devs[idx] = wmxsdk;
+
+	/* Notify listeners of new devices */
+	iwmx_sdk_call_new_callbacks (wmxsdk);
+	return;
+
+error:
+	wmxsdk_unref(wmxsdk);
+	return;
+}
+
+static void iwmx_sdk_dev_rm(unsigned idx)
+{
+	struct wmxsdk *wmxsdk;
+
+	if (idx >= IWMX_SDK_DEV_MAX) {
+		nm_log_err(LOGD_WIMAX, "BUG! idx (%u) >= IWMX_SDK_DEV_MAX (%u)", idx, IWMX_SDK_DEV_MAX);
+		return;
+	}
+
+	wmxsdk = g_iwmx_sdk_devs[idx];
+	_schedule_removed(wmxsdk);
+	iwmx_sdk_remove(wmxsdk);
+	wmxsdk_unref(wmxsdk);
+	g_iwmx_sdk_devs[idx] = NULL;
+}
+
+static void iwmx_sdk_addremove_cb(WIMAX_API_DEVICE_ID *devid,
+				  BOOL presence)
+{
+	unsigned int cnt;
+	WIMAX_API_RET r;
+	WIMAX_API_HW_DEVICE_ID device_id_list[5];
+	UINT32 device_id_list_size = ARRAY_SIZE(device_id_list);
+	char errstr[512];
+	UINT32 errstr_size = sizeof(errstr);
+
+	g_mutex_lock(&add_remove_mutex);
+
+	nm_log_dbg(LOGD_WIMAX, "cb: handle %u index #%u is %d", devid->sdkHandle,
+	           devid->deviceIndex, presence);
+
+	r = GetListDevice(devid, device_id_list, &device_id_list_size);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(devid, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot obtain list of devices: %d (%s)", r, errstr);
+		goto out;
+	}
+
+	if (device_id_list_size == 0) {
+		nm_log_dbg(LOGD_WIMAX, "No WiMAX devices reported");
+	} else {
+		for (cnt = 0; cnt < device_id_list_size; cnt++) {
+			WIMAX_API_HW_DEVICE_ID *dev =
+				device_id_list + cnt;
+			nm_log_dbg(LOGD_WIMAX, "#%u index #%u device %s", cnt,
+			           dev->deviceIndex, dev->deviceName);
+		}
+	}
+
+	if (presence) {
+		WIMAX_API_HW_DEVICE_ID *dev;
+
+		/* Make sure the wimax NS isn't lying to us */
+		if (device_id_list_size < devid->deviceIndex) {
+			nm_log_err(LOGD_WIMAX, "wmxsdk: changed device (%u) not in the list? (%u items)",
+			           devid->deviceIndex, device_id_list_size);
+			goto out;
+		}
+
+		/* Add the device to our internal list */
+		dev = device_id_list + devid->deviceIndex;
+		iwmx_sdk_dev_add(devid->deviceIndex, dev->deviceIndex, dev->deviceName);
+	} else {
+		/* Remove the device from our internal list */
+		int idx = deviceid_to_index(devid);
+
+		if (idx >= 0)
+			iwmx_sdk_dev_rm(idx);
+	}
+
+out:
+	g_mutex_unlock(&add_remove_mutex);
+}
+
+/*
+ * Initialize the WiMAX API, register with it, setup callbacks for
+ * device coming up / dissapearing
+ */
+int iwmx_sdk_api_init(void)
+{
+	int result;
+	unsigned int cnt;
+	WIMAX_API_RET r;
+	char errstr[512];
+	UINT32 errstr_size = sizeof(errstr);
+
+	WIMAX_API_HW_DEVICE_ID device_id_list[5];
+	UINT32 device_id_list_size = ARRAY_SIZE(device_id_list);
+
+	memset(&g_api, 0, sizeof(g_api));
+	g_api.privilege = WIMAX_API_PRIVILEGE_READ_WRITE;
+
+	result = -EIO;
+	r = WiMaxAPIOpen(&g_api);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&g_api, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: WiMaxAPIOpen failed with %d (%s)", r, errstr);
+		goto error_wimaxapiopen;
+	}
+
+	r = SubscribeDeviceInsertRemove(&g_api, iwmx_sdk_addremove_cb);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&g_api, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: insert/remove subscribe failed with %d (%s)", r, errstr);
+		goto error_close;
+	}
+
+	r = GetListDevice(&g_api, device_id_list, &device_id_list_size);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&g_api, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot obtain list of devices: %d (%s)", r, errstr);
+		goto error_close;
+	}
+	if (device_id_list_size < g_api.deviceIndex) {
+		nm_log_err(LOGD_WIMAX, "wmxsdk: changed device (%u) not in the list? (%u items)",
+		           g_api.deviceIndex, device_id_list_size);
+	}
+
+	if (device_id_list_size == 0) {
+		nm_log_dbg(LOGD_WIMAX, "No WiMAX devices reported");
+	} else {
+		for (cnt = 0; cnt < device_id_list_size; cnt++) {
+			WIMAX_API_HW_DEVICE_ID *dev = device_id_list + cnt;
+			nm_log_dbg(LOGD_WIMAX, "#%u index #%u device %s", cnt, dev->deviceIndex, dev->deviceName);
+			iwmx_sdk_dev_add(cnt, dev->deviceIndex, dev->deviceName);
+		}
+	}
+	return 0;
+
+error_close:
+	WiMaxAPIClose(&g_api);
+error_wimaxapiopen:
+	return result;
+}
+
+void iwmx_sdk_api_exit(void)
+{
+	WIMAX_API_RET r;
+
+	char errstr[512];
+	UINT32 errstr_size = sizeof(errstr);
+
+	r = WiMaxAPIClose(&g_api);
+	if (r != WIMAX_API_RET_SUCCESS) {
+		GetErrorString(&g_api, r, errstr, &errstr_size);
+		nm_log_err(LOGD_WIMAX, "wmxsdk: WiMaxAPIClose failed with %d (%s)", r, errstr);
+	}
+	return;
+}
diff --git a/src/devices/wimax/iwmxsdk.h b/src/devices/wimax/iwmxsdk.h
new file mode 100644
index 00000000..785ca8c2
--- /dev/null
+++ b/src/devices/wimax/iwmxsdk.h
@@ -0,0 +1,111 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ *
+ *  Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+ *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef IWMXSDK_H
+#define IWMXSDK_H
+
+#include <wimax/WiMaxType.h>
+#include <wimax/WiMaxTypesEx.h>
+#include <wimax/WiMaxAPIEx.h>
+
+struct wmxsdk;
+
+typedef void (*WimaxNewWmxsdkFunc) (struct wmxsdk *wmxsdk, void *user_data);
+
+typedef void (*WimaxStateChangeFunc) (struct wmxsdk *wmxsdk,
+                                      WIMAX_API_DEVICE_STATUS new_status,
+                                      WIMAX_API_DEVICE_STATUS old_status,
+                                      WIMAX_API_STATUS_REASON reason,
+                                      WIMAX_API_CONNECTION_PROGRESS_INFO info,
+                                      void *user_data);
+
+typedef void (*WimaxMediaStatusFunc) (struct wmxsdk *wmxsdk,
+                                      WIMAX_API_MEDIA_STATUS media_status,
+                                      void *user_data);
+
+typedef void (*WimaxConnectResultFunc) (struct wmxsdk *wmxsdk,
+                                        WIMAX_API_NETWORK_CONNECTION_RESP resp,
+                                        void *user_data);
+
+typedef void (*WimaxScanResultFunc) (struct wmxsdk *wmxsdk,
+                                     WIMAX_API_NSP_INFO_EX *nsps,
+                                     guint num_nsps,
+                                     void *user_data);
+
+typedef void (*WimaxRemovedFunc) (struct wmxsdk *wmxsdk, void *user_data);
+
+struct wmxsdk {
+	gint refcount;
+
+	WIMAX_API_DEVICE_ID device_id;
+
+	WimaxStateChangeFunc state_change_cb;
+	WimaxMediaStatusFunc media_status_cb;
+	WimaxConnectResultFunc connect_result_cb;
+	WimaxScanResultFunc scan_result_cb;
+	WimaxRemovedFunc removed_cb;
+	void *callback_data;
+
+	GMutex network_mutex;
+
+	WIMAX_API_DEVICE_STATUS status;
+	WIMAX_API_MEDIA_STATUS media_status;
+	GMutex status_mutex;
+
+	GMutex connect_mutex;
+
+	char name[100];
+	char ifname[16];
+};
+
+struct wmxsdk *iwmx_sdk_get_wmxsdk_for_iface(const char *iface);
+
+struct wmxsdk *wmxsdk_ref(struct wmxsdk *wmxsdk);
+void wmxsdk_unref(struct wmxsdk *wmxsdk);
+
+/* Register/unregister callbacks when a new wmxsdk is set up */
+void iwmx_sdk_new_callback_register(WimaxNewWmxsdkFunc callback, void *user_data);
+void iwmx_sdk_new_callback_unregister(WimaxNewWmxsdkFunc callback, void *user_data);
+
+void iwmx_sdk_set_callbacks(struct wmxsdk *wmxsdk,
+                            WimaxStateChangeFunc state_change_cb,
+                            WimaxMediaStatusFunc media_status_func,
+                            WimaxConnectResultFunc connect_result_cb,
+                            WimaxScanResultFunc scan_result_cb,
+                            WimaxRemovedFunc removed_cb,
+                            void *user_data);
+
+WIMAX_API_DEVICE_STATUS iwmxsdk_status_get(struct wmxsdk *wmxsdk);
+int iwmx_sdk_connect(struct wmxsdk *wmxsdk, const char *nsp_name);
+int iwmx_sdk_disconnect(struct wmxsdk *wmxsdk);
+int iwmx_sdk_set_fast_reconnect_enabled(struct wmxsdk *wmxsdk, int enabled);
+WIMAX_API_CONNECTED_NSP_INFO_EX *iwmx_sdk_get_connected_network(struct wmxsdk *wmxsdk);
+WIMAX_API_LINK_STATUS_INFO_EX *iwmx_sdk_get_link_status_info(struct wmxsdk *wmxsdk);
+const char *iwmx_sdk_dev_status_to_str(WIMAX_API_DEVICE_STATUS status);
+const char *iwmx_sdk_reason_to_str(WIMAX_API_STATUS_REASON reason);
+const char *iwmx_sdk_media_status_to_str(WIMAX_API_MEDIA_STATUS status);
+const char *iwmx_sdk_con_progress_to_str(WIMAX_API_CONNECTION_PROGRESS_INFO progress);
+int iwmx_sdk_rf_state_set(struct wmxsdk *wmxsdk, WIMAX_API_RF_STATE rf_state);
+int iwmx_sdk_get_networks(struct wmxsdk *wmxsdk);
+int iwmx_sdk_api_init(void);
+void iwmx_sdk_api_exit(void);
+
+#endif  /* IWMXSDK_H */
diff --git a/src/devices/wimax/nm-device-wimax.c b/src/devices/wimax/nm-device-wimax.c
new file mode 100644
index 00000000..1bdda489
--- /dev/null
+++ b/src/devices/wimax/nm-device-wimax.c
@@ -0,0 +1,1445 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2010 - 2011 Red Hat, Inc.
+ * Copyright (C) 2009 Novell, Inc.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <net/ethernet.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <netinet/ether.h>
+
+#include <WiMaxAPI.h>
+#include <WiMaxAPIEx.h>
+
+#include "nm-device-wimax.h"
+#include "nm-wimax-util.h"
+#include "nm-logging.h"
+#include "nm-device-private.h"
+#include "NetworkManagerUtils.h"
+#include "nm-dbus-manager.h"
+#include "nm-connection.h"
+#include "nm-setting-connection.h"
+#include "nm-setting-wimax.h"
+#include "nm-utils.h"
+#include "nm-rfkill-manager.h"
+#include "iwmxsdk.h"
+#include "nm-enum-types.h"
+#include "nm-dbus-glib-types.h"
+
+static gboolean impl_device_get_nsp_list (NMDeviceWimax *device, GPtrArray **list, GError **error);
+
+#include "nm-device-wimax-glue.h"
+
+G_DEFINE_TYPE (NMDeviceWimax, nm_device_wimax, NM_TYPE_DEVICE)
+
+enum {
+	PROP_0,
+	PROP_NSPS,
+	PROP_ACTIVE_NSP,
+	PROP_CENTER_FREQ,
+	PROP_RSSI,
+	PROP_CINR,
+	PROP_TX_POWER,
+	PROP_BSID,
+
+	LAST_PROP
+};
+
+enum {
+	NSP_ADDED,
+	NSP_REMOVED,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+#define NM_DEVICE_WIMAX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+                                        NM_TYPE_DEVICE_WIMAX, \
+                                        NMDeviceWimaxPrivate))
+
+typedef struct {
+	gboolean disposed;
+
+	struct wmxsdk *sdk;
+	WIMAX_API_DEVICE_STATUS status;
+	gboolean connect_failed;
+
+	gboolean enabled;
+	gboolean wimaxd_enabled;
+	guint activation_timeout_id;
+
+	/* Track whether stage1 (Prepare) is completed yet or not */
+	gboolean prepare_done;
+
+	guint sdk_action_defer_id;
+
+	guint link_timeout_id;
+	guint poll_id;
+
+	GSList *nsp_list;
+	NMWimaxNsp *current_nsp;
+
+	/* interesting stuff when connected */
+	guint center_freq;
+	gint rssi;
+	gint cinr;
+	gint tx_power;
+	char *bsid;
+} NMDeviceWimaxPrivate;
+
+/***********************************************************/
+
+#define NM_WIMAX_ERROR (nm_wimax_error_quark ())
+
+static GQuark
+nm_wimax_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("nm-wimax-error");
+	return quark;
+}
+
+/***********************************************************/
+
+static gboolean
+impl_device_get_nsp_list (NMDeviceWimax *self, GPtrArray **nsps, GError **error)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+	GSList *iter;
+
+	*nsps = g_ptr_array_sized_new (4);
+	for (iter = priv->nsp_list; iter; iter = iter->next)
+		g_ptr_array_add (*nsps, g_strdup (nm_wimax_nsp_get_dbus_path (NM_WIMAX_NSP (iter->data))));
+
+	return TRUE;
+}
+
+static void
+set_current_nsp (NMDeviceWimax *self, NMWimaxNsp *new_nsp)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+	NMWimaxNsp *old_nsp;
+	gboolean path_changed = FALSE;
+
+	old_nsp = priv->current_nsp;
+	priv->current_nsp = NULL;
+
+	if (new_nsp)
+		priv->current_nsp = g_object_ref (new_nsp);
+
+	if (old_nsp && new_nsp) {
+		path_changed = (g_strcmp0 (nm_wimax_nsp_get_dbus_path (old_nsp),
+		                           nm_wimax_nsp_get_dbus_path (new_nsp)) != 0);
+	}
+
+	/* Only notify if it's really changed */
+	if (old_nsp != new_nsp || path_changed)
+		g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_ACTIVE_NSP);
+
+	if (old_nsp)
+		g_object_unref (old_nsp);
+}
+
+static gboolean
+activation_timed_out (gpointer data)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (data);
+
+	priv->activation_timeout_id = 0;
+	nm_device_state_changed (NM_DEVICE (data), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+
+	return FALSE;
+}
+
+static void
+emit_nsp_added_removed (NMDeviceWimax *self,
+                        guint signum,
+                        NMWimaxNsp *nsp,
+                        gboolean recheck_available_connections)
+{
+	g_signal_emit (self, signals[signum], 0, nsp);
+	g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_NSPS);
+	nm_device_emit_recheck_auto_activate (NM_DEVICE (self));
+	if (recheck_available_connections)
+		nm_device_recheck_available_connections (NM_DEVICE (self));
+}
+
+static void
+remove_all_nsps (NMDeviceWimax *self)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+
+	set_current_nsp (self, NULL);
+
+	while (priv->nsp_list) {
+		NMWimaxNsp *nsp = NM_WIMAX_NSP (priv->nsp_list->data);
+
+		priv->nsp_list = g_slist_remove (priv->nsp_list, nsp);
+		emit_nsp_added_removed (self, NSP_REMOVED, nsp, FALSE);
+		g_object_unref (nsp);
+	}
+
+	nm_device_recheck_available_connections (NM_DEVICE (self));
+}
+
+static NMWimaxNsp *
+get_nsp_by_name (NMDeviceWimax *self, const char *name)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+	GSList *iter;
+
+	g_return_val_if_fail (name, NULL);
+
+	for (iter = priv->nsp_list; iter; iter = iter->next) {
+		NMWimaxNsp *nsp = NM_WIMAX_NSP (iter->data);
+
+		if (!g_strcmp0 (nm_wimax_nsp_get_name (nsp), name))
+			return nsp;
+	}
+
+	return NULL;
+}
+
+static NMWimaxNsp *
+get_nsp_by_path (NMDeviceWimax *self, const char *path)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+	GSList *iter;
+
+	g_return_val_if_fail (path, NULL);
+
+	for (iter = priv->nsp_list; iter; iter = iter->next) {
+		NMWimaxNsp *nsp = NM_WIMAX_NSP (iter->data);
+
+		if (!strcmp (nm_wimax_nsp_get_dbus_path (nsp), path))
+			return nsp;
+	}
+
+	return NULL;
+}
+
+static gboolean
+update_availability (NMDeviceWimax *self, gboolean old_available)
+{
+	NMDevice *device = NM_DEVICE (self);
+	NMDeviceState state;
+	gboolean new_available, changed = FALSE;
+
+	new_available = nm_device_is_available (device);
+	if (new_available == old_available)
+		return FALSE;
+
+	state = nm_device_get_state (device);
+	if (state == NM_DEVICE_STATE_UNAVAILABLE) {
+		if (new_available == TRUE) {
+			nm_device_state_changed (device,
+			                         NM_DEVICE_STATE_DISCONNECTED,
+			                         NM_DEVICE_STATE_REASON_NONE);
+			changed = TRUE;
+		}
+	} else if (state >= NM_DEVICE_STATE_DISCONNECTED) {
+		if (new_available == FALSE) {
+			nm_device_state_changed (device,
+			                         NM_DEVICE_STATE_UNAVAILABLE,
+			                         NM_DEVICE_STATE_REASON_NONE);
+			changed = TRUE;
+		}
+	}
+
+	return changed;
+}
+
+/* NMDeviceInterface interface */
+
+static void
+set_enabled (NMDevice *device, gboolean enabled)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (device);
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+	gboolean old_available;
+	int ret;
+	const char *iface;
+
+	iface = nm_device_get_iface (NM_DEVICE (self));
+
+	nm_log_dbg (LOGD_WIMAX, "(%s): setting radio enabled %d -> %d",
+	            iface, priv->enabled, enabled);
+	if (priv->enabled == enabled)
+		return;
+
+	old_available = nm_device_is_available (NM_DEVICE (device));
+	priv->enabled = enabled;
+
+	nm_log_dbg (LOGD_WIMAX, "(%s): radio now %s",
+	            iface, priv->enabled ? "enabled" : "disabled");
+
+	/* Set the WiMAX device RF state to the current user-specified enabled state */
+	if (priv->sdk) {
+		ret = iwmx_sdk_rf_state_set (priv->sdk,
+		                             enabled ? WIMAX_API_RF_ON : WIMAX_API_RF_OFF);
+		if (ret < 0 && ret != -EINPROGRESS) {
+			nm_log_warn (LOGD_WIMAX, "(%s): failed to %s radio",
+			             iface, priv->enabled ? "enable" : "disable");
+		}
+	}
+
+	update_availability (self, old_available);
+}
+
+/* NMDevice methods */
+
+static gboolean
+check_connection_compatible (NMDevice *device, NMConnection *connection)
+{
+	NMSettingConnection *s_con;
+	NMSettingWimax *s_wimax;
+	const char *connection_type;
+	const GByteArray *mac;
+
+	if (!NM_DEVICE_CLASS (nm_device_wimax_parent_class)->check_connection_compatible (device, connection))
+		return FALSE;
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+
+	connection_type = nm_setting_connection_get_connection_type (s_con);
+	if (strcmp (connection_type, NM_SETTING_WIMAX_SETTING_NAME))
+		return FALSE;
+
+	s_wimax = nm_connection_get_setting_wimax (connection);
+	if (!s_wimax)
+		return FALSE;
+
+	mac = nm_setting_wimax_get_mac_address (s_wimax);
+	if (mac && memcmp (mac->data, nm_device_get_hw_address (device, NULL), ETH_ALEN))
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
+check_connection_available (NMDevice *device,
+                            NMConnection *connection,
+                            const char *specific_object)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device);
+	const GSList *ns_iter = NULL;
+	NMWimaxNsp *nsp;
+
+	if (specific_object) {
+		nsp = get_nsp_by_path (NM_DEVICE_WIMAX (device), specific_object);
+		return nsp ? nm_wimax_nsp_check_compatible (nsp, connection) : FALSE;
+	}
+
+	/* Ensure the connection applies to an NSP in the scan list */
+	for (ns_iter = priv->nsp_list; ns_iter; ns_iter = ns_iter->next) {
+		if (nm_wimax_nsp_check_compatible (NM_WIMAX_NSP (ns_iter->data), connection))
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+static gboolean
+complete_connection (NMDevice *device,
+                     NMConnection *connection,
+                     const char *specific_object,
+                     const GSList *existing_connections,
+                     GError **error)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (device);
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+	NMSettingWimax *s_wimax;
+	const GByteArray *setting_mac;
+	const guint8 *hw_address;
+	char *format;
+	const char *nsp_name = NULL;
+	NMWimaxNsp *nsp = NULL;
+	GSList *iter;
+
+	s_wimax = nm_connection_get_setting_wimax (connection);
+
+	if (!specific_object) {
+		/* If not given a specific object, we need at minimum an NSP name */
+		if (!s_wimax) {
+			g_set_error_literal (error,
+			                     NM_WIMAX_ERROR,
+			                     NM_WIMAX_ERROR_CONNECTION_INVALID,
+			                     "A 'wimax' setting is required if no NSP path was given.");
+			return FALSE;
+		}
+
+		nsp_name = nm_setting_wimax_get_network_name (s_wimax);
+		if (!nsp_name || !strlen (nsp_name)) {
+			g_set_error_literal (error,
+			                     NM_WIMAX_ERROR,
+			                     NM_WIMAX_ERROR_CONNECTION_INVALID,
+			                     "A 'wimax' setting with a valid network name is required if no NSP path was given.");
+			return FALSE;
+		}
+
+		/* Find a compatible NSP in the list */
+		nsp = get_nsp_by_name (self, nsp_name);
+
+		/* If we still don't have an NSP, then the WiMAX settings needs to be
+		 * fully specified by the client.  Might not be able to find the NSP
+		 * if the scan didn't find the NSP yet.
+		 */
+		if (!nsp) {
+			if (!nm_setting_verify (NM_SETTING (s_wimax), NULL, error))
+				return FALSE;
+		}
+	} else {
+		/* Find a compatible NSP in the list */
+		for (iter = priv->nsp_list; iter; iter = g_slist_next (iter)) {
+			if (!strcmp (specific_object, nm_wimax_nsp_get_dbus_path (NM_WIMAX_NSP (iter->data)))) {
+				nsp = NM_WIMAX_NSP (iter->data);
+				break;
+			}
+		}
+
+		if (!nsp) {
+			g_set_error (error,
+			             NM_WIMAX_ERROR,
+			             NM_WIMAX_ERROR_NSP_NOT_FOUND,
+			             "The NSP %s was not in the scan list.",
+			             specific_object);
+			return FALSE;
+		}
+
+		nsp_name = nm_wimax_nsp_get_name (nsp);
+	}
+
+	/* Add a WiMAX setting if one doesn't exist */
+	if (!s_wimax) {
+		s_wimax = (NMSettingWimax *) nm_setting_wimax_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_wimax));
+	}
+
+	g_assert (nsp_name);
+	format = g_strdup_printf ("%s %%d", nsp_name);
+	nm_utils_complete_generic (connection,
+	                           NM_SETTING_WIMAX_SETTING_NAME,
+	                           existing_connections,
+	                           format,
+	                           nsp_name,
+	                           TRUE);
+	g_free (format);
+	g_object_set (G_OBJECT (s_wimax), NM_SETTING_WIMAX_NETWORK_NAME, nsp_name, NULL);
+
+	setting_mac = nm_setting_wimax_get_mac_address (s_wimax);
+	hw_address = nm_device_get_hw_address (device, NULL);
+	if (setting_mac) {
+		/* Make sure the setting MAC (if any) matches the device's permanent MAC */
+		if (memcmp (setting_mac->data, hw_address, ETH_ALEN)) {
+			g_set_error (error,
+				         NM_SETTING_WIMAX_ERROR,
+				         NM_SETTING_WIMAX_ERROR_INVALID_PROPERTY,
+				         NM_SETTING_WIMAX_MAC_ADDRESS);
+			return FALSE;
+		}
+	} else {
+		GByteArray *mac;
+		const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+
+		/* Lock the connection to this device by default */
+		if (memcmp (hw_address, null_mac, ETH_ALEN)) {
+			mac = g_byte_array_sized_new (ETH_ALEN);
+			g_byte_array_append (mac, hw_address, ETH_ALEN);
+			g_object_set (G_OBJECT (s_wimax), NM_SETTING_WIMAX_MAC_ADDRESS, mac, NULL);
+			g_byte_array_free (mac, TRUE);
+		}
+	}
+
+	return TRUE;
+}
+
+static gboolean
+can_auto_connect (NMDevice *device,
+                  NMConnection *connection,
+                  char **specific_object)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device);
+	GSList *iter;
+
+	if (!NM_DEVICE_CLASS (nm_device_wimax_parent_class)->can_auto_connect (device, connection, specific_object))
+		return FALSE;
+
+	for (iter = priv->nsp_list; iter; iter = iter->next) {
+		NMWimaxNsp *nsp = NM_WIMAX_NSP (iter->data);
+
+		if (nm_wimax_nsp_check_compatible (nsp, connection)) {
+			*specific_object = (char *) nm_wimax_nsp_get_dbus_path (nsp);
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+static gboolean
+is_available (NMDevice *device)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device);
+	const char *iface = nm_device_get_iface (device);
+
+	if (!priv->enabled) {
+		nm_log_dbg (LOGD_WIMAX, "(%s): not available because not enabled", iface);
+		return FALSE;
+	}
+
+	if (!priv->wimaxd_enabled) {
+		nm_log_dbg (LOGD_WIMAX, "(%s): not available because not enabled in wimaxd", iface);
+		return FALSE;
+	}
+
+	if (!nm_wimax_util_sdk_is_initialized ()) {
+		nm_log_dbg (LOGD_WIMAX, "(%s): not available because WiMAX SDK not initialized", iface);
+		return FALSE;
+	}
+
+	if (!priv->sdk) {
+		nm_log_dbg (LOGD_WIMAX, "(%s): not available because not known to WiMAX SDK", iface);
+		return FALSE;
+	}
+
+	return iwmxsdk_status_get (priv->sdk) >= WIMAX_API_DEVICE_STATUS_Ready;
+}
+
+static void
+clear_activation_timeout (NMDeviceWimax *self)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+
+	if (priv->activation_timeout_id) {
+		g_source_remove (priv->activation_timeout_id);
+		priv->activation_timeout_id = 0;
+	}
+
+	priv->connect_failed = FALSE;
+}
+
+static void
+clear_link_timeout (NMDeviceWimax *self)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+
+	if (priv->link_timeout_id) {
+		g_source_remove (priv->link_timeout_id);
+		priv->link_timeout_id = 0;
+	}
+}
+
+static void
+clear_connected_poll (NMDeviceWimax *self)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+
+	if (priv->poll_id) {
+		g_source_remove (priv->poll_id);
+		priv->poll_id = 0;
+	}
+}
+
+static NMActStageReturn
+act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device);
+	NMActRequest *req;
+	GSList *iter;
+	const char *path;
+	NMWimaxNsp *nsp = NULL;
+
+	clear_link_timeout (NM_DEVICE_WIMAX (device));
+
+	*reason = NM_DEVICE_STATE_REASON_NONE;
+
+	req = nm_device_get_act_request (device);
+	if (!req)
+		return NM_ACT_STAGE_RETURN_FAILURE;
+
+	path = nm_active_connection_get_specific_object (NM_ACTIVE_CONNECTION (req));
+	if (!path)
+		return NM_ACT_STAGE_RETURN_FAILURE;
+
+	/* Find the NSP in the scan list */
+	for (iter = priv->nsp_list; iter; iter = iter->next) {
+		NMWimaxNsp *candidate = NM_WIMAX_NSP (iter->data);
+
+		if (!strcmp (path, nm_wimax_nsp_get_dbus_path (candidate))) {
+			nsp = candidate;
+			break;
+		}
+	}
+
+	/* Couldn't find the NSP for some reason */
+	if (nsp == NULL)
+		return NM_ACT_STAGE_RETURN_FAILURE;
+
+	set_current_nsp (NM_DEVICE_WIMAX (device), nsp);
+
+	priv->prepare_done = TRUE;
+
+	/* If the device is scanning, it won't connect, so we have to wait until
+	 * it's not scanning to proceed to stage 2.
+	 */
+	if (priv->status == WIMAX_API_DEVICE_STATUS_Scanning)
+		return NM_ACT_STAGE_RETURN_POSTPONE;
+
+	return NM_ACT_STAGE_RETURN_SUCCESS;
+}
+
+static NMActStageReturn
+act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device);
+	NMConnection *connection;
+	NMSettingWimax *s_wimax;
+	const char *nsp_name, *iface;
+	int ret;
+
+	iface = nm_device_get_iface (device);
+	g_assert (iface);
+
+	connection = nm_device_get_connection (device);
+	g_assert (connection);
+
+	s_wimax = nm_connection_get_setting_wimax (connection);
+	g_assert (s_wimax);
+
+	nsp_name = nm_setting_wimax_get_network_name (s_wimax);
+	g_assert (nsp_name);
+
+	nm_log_info (LOGD_WIMAX, "(%s): connecting to NSP '%s'",
+	             iface, nsp_name);
+
+	priv->connect_failed = FALSE;
+	ret = iwmx_sdk_connect (priv->sdk, nsp_name);
+	if (ret < 0 && ret != -EINPROGRESS) {
+		nm_log_err (LOGD_WIMAX, "(%s): failed to connect to NSP '%s'",
+		            iface, nsp_name);
+		*reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
+		return NM_ACT_STAGE_RETURN_FAILURE;
+	}
+
+	/* FIXME: Is 40 seconds good estimation? I have no idea */
+	priv->activation_timeout_id = g_timeout_add_seconds (40, activation_timed_out, device);
+
+	return NM_ACT_STAGE_RETURN_POSTPONE;
+}
+
+static void
+force_disconnect (NMDeviceWimax *self, struct wmxsdk *sdk)
+{
+	WIMAX_API_DEVICE_STATUS status;
+	int ret;
+	const char *iface;
+
+	g_return_if_fail (sdk != NULL);
+
+	iface = nm_device_get_iface (NM_DEVICE (self));
+
+	status = iwmxsdk_status_get (sdk);
+	if ((int) status < 0) {
+		nm_log_err (LOGD_WIMAX, "(%s): failed to read WiMAX device status: %d",
+		            iface, status);
+		return;
+	}
+
+	if (   status == WIMAX_API_DEVICE_STATUS_Connecting
+	    || status == WIMAX_API_DEVICE_STATUS_Data_Connected) {
+		nm_log_dbg (LOGD_WIMAX, "(%s): requesting disconnect", iface);
+		ret = iwmx_sdk_disconnect (sdk);
+		if (ret < 0 && ret != -EINPROGRESS) {
+			nm_log_err (LOGD_WIMAX, "(%s): failed to disconnect WiMAX device: %d",
+			            iface, ret);
+		}
+	}
+}
+
+static void
+deactivate (NMDevice *device)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (device);
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+
+	clear_activation_timeout (self);
+	clear_link_timeout (self);
+	clear_connected_poll (self);
+
+	set_current_nsp (self, NULL);
+
+	if (priv->sdk) {
+		/* Read explicit status here just to make sure we have the most
+		 * up-to-date status and to ensure we disconnect if needed.
+		 */
+		force_disconnect (self, priv->sdk);
+	}
+}
+
+/*************************************************************************/
+
+static void
+wmx_state_change_cb (struct wmxsdk *wmxsdk,
+                     WIMAX_API_DEVICE_STATUS new_status,
+                     WIMAX_API_DEVICE_STATUS old_status,
+                     WIMAX_API_STATUS_REASON reason,
+                     WIMAX_API_CONNECTION_PROGRESS_INFO progress,
+                     void *user_data)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+	NMDeviceState state;
+	const char *iface;
+	gboolean old_available = FALSE;
+	const char *nsp_name = NULL;
+
+	iface = nm_device_get_iface (NM_DEVICE (self));
+	nm_log_info (LOGD_WIMAX, "(%s): wimax state change %s -> %s (%s (%d))",
+	             iface,
+	             iwmx_sdk_dev_status_to_str (old_status),
+	             iwmx_sdk_dev_status_to_str (new_status),
+	             iwmx_sdk_con_progress_to_str (progress),
+	             progress);
+
+	if (new_status == old_status)
+		return;
+
+	state = nm_device_get_state (NM_DEVICE (self));
+	old_available = nm_device_is_available (NM_DEVICE (self));
+
+	priv->status = new_status;
+	if (priv->current_nsp)
+		nsp_name = nm_wimax_nsp_get_name (priv->current_nsp);
+
+	switch (new_status) {
+	case WIMAX_API_DEVICE_STATUS_UnInitialized:
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
+	case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
+		if (priv->wimaxd_enabled) {
+			priv->wimaxd_enabled = FALSE;
+			if (update_availability (self, old_available))
+				return;
+		}
+		break;
+	case WIMAX_API_DEVICE_STATUS_Connecting:
+	case WIMAX_API_DEVICE_STATUS_Data_Connected:
+		/* If for some reason we're initially connected, force a disconnect here */
+		if (state < NM_DEVICE_STATE_DISCONNECTED)
+			force_disconnect (self, wmxsdk);
+		/* Fall through */
+	case WIMAX_API_DEVICE_STATUS_Ready:
+	case WIMAX_API_DEVICE_STATUS_Scanning:
+		if (priv->wimaxd_enabled == FALSE) {
+			priv->wimaxd_enabled = TRUE;
+			if (update_availability (self, old_available))
+				return;
+		}
+		break;
+	default:
+		nm_log_warn (LOGD_WIMAX, "(%s): unhandled WiMAX device state %d",
+		             iface, new_status);
+		break;
+	}
+
+	/* Handle activation success and failure */
+	if (nm_device_is_activating (NM_DEVICE (self))) {
+	    if (new_status == WIMAX_API_DEVICE_STATUS_Data_Connected) {
+			/* Success */
+			clear_activation_timeout (self);
+
+			nm_log_info (LOGD_WIMAX, "(%s): connected to '%s'",
+			             iface, nsp_name);
+			nm_device_activate_schedule_stage3_ip_config_start (NM_DEVICE (self));
+			return;
+		}
+
+		if (priv->connect_failed) {
+			/* Connection attempt failed */
+			nm_log_info (LOGD_WIMAX, "(%s): connection to '%s' failed: (%d) %s",
+			             iface, nsp_name, reason, iwmx_sdk_reason_to_str (reason));
+			nm_device_state_changed (NM_DEVICE (self),
+			                         NM_DEVICE_STATE_FAILED,
+			                         NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+			return;
+		}
+
+		/* If stage2 was postponed because the device was scanning or something,
+		 * then check if we need to move to stage2 now that the device might be
+		 * ready.
+		 */
+		if (state == NM_DEVICE_STATE_PREPARE && priv->prepare_done) {
+			if (   new_status == WIMAX_API_DEVICE_STATUS_Ready
+			    || new_status == WIMAX_API_DEVICE_STATUS_Connecting) {
+				nm_device_activate_schedule_stage2_device_config (NM_DEVICE (self));
+				return;
+			}
+		}
+	}
+
+	/* Handle disconnection */
+	if (state == NM_DEVICE_STATE_ACTIVATED) {
+		if (   old_status == WIMAX_API_DEVICE_STATUS_Data_Connected
+			&& new_status < WIMAX_API_DEVICE_STATUS_Connecting) {
+
+			nm_log_info (LOGD_WIMAX, "(%s): disconnected from '%s': (%d) %s",
+				         iface, nsp_name, reason, iwmx_sdk_reason_to_str (reason));
+
+			nm_device_state_changed (NM_DEVICE (self),
+				                     NM_DEVICE_STATE_FAILED,
+				                     NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+		}
+	}
+}
+
+static gboolean
+link_timeout_cb (gpointer user_data)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+
+	priv->link_timeout_id = 0;
+
+	nm_log_dbg (LOGD_WIMAX, "(%s): link timed out", nm_device_get_iface (NM_DEVICE (self)));
+	nm_device_state_changed (NM_DEVICE (self),
+	                         NM_DEVICE_STATE_FAILED,
+	                         NM_DEVICE_STATE_REASON_CARRIER);
+
+	return FALSE;
+}
+
+static void
+wmx_media_status_cb (struct wmxsdk *wmxsdk,
+                     WIMAX_API_MEDIA_STATUS new_status,
+                     void *user_data)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+	NMDeviceState state;
+	const char *iface;
+
+	iface = nm_device_get_iface (NM_DEVICE (self));
+	state = nm_device_get_state (NM_DEVICE (self));
+
+	nm_log_dbg (LOGD_WIMAX, "(%s): media status change to %s",
+	            iface, iwmx_sdk_media_status_to_str (new_status));
+
+	/* We only care about media events while activated */
+	if (state != NM_DEVICE_STATE_ACTIVATED)
+		return;
+
+	clear_link_timeout (self);
+
+	switch (new_status) {
+	case WIMAX_API_MEDIA_STATUS_LINK_UP:
+		break;
+	case WIMAX_API_MEDIA_STATUS_LINK_DOWN:
+		nm_log_dbg (LOGD_WIMAX, "(%s): starting link timeout", iface);
+		priv->link_timeout_id = g_timeout_add_seconds (15, link_timeout_cb, self);
+		break;
+	case WIMAX_API_MEDIA_STATUS_LINK_RENEW:
+		nm_log_dbg (LOGD_WIMAX, "(%s): renewing DHCP lease", iface);
+		if (!nm_device_dhcp4_renew (NM_DEVICE (self), TRUE)) {
+			nm_device_state_changed (NM_DEVICE (self),
+			                         NM_DEVICE_STATE_FAILED,
+			                         NM_DEVICE_STATE_REASON_DHCP_FAILED);
+		}
+		break;
+	default:
+		nm_log_err (LOGD_WIMAX, "(%s): unhandled media status %d", iface, new_status);
+		break;
+	}
+}
+
+static void
+wmx_connect_result_cb (struct wmxsdk *wmxsdk,
+                       WIMAX_API_NETWORK_CONNECTION_RESP result,
+                       void *user_data)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+
+	if (nm_device_is_activating (NM_DEVICE (self))) {
+		priv->connect_failed = (result == WIMAX_API_CONNECTION_SUCCESS);
+		/* Wait for the state change so we can get the reason code; we
+		 * cache the connect failure so we don't have to wait for the
+		 * activation timeout.
+		 */
+	}
+}
+
+static void
+remove_outdated_nsps (NMDeviceWimax *self,
+					  WIMAX_API_NSP_INFO_EX *nsp_list,
+					  guint32 list_size)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+	GSList *iter;
+	GSList *to_remove = NULL;
+
+	for (iter = priv->nsp_list; iter; iter = iter->next) {
+		NMWimaxNsp *nsp = NM_WIMAX_NSP (iter->data);
+		gboolean found = FALSE;
+		int i;
+
+		for (i = 0; i < list_size; i++) {
+			WIMAX_API_NSP_INFO_EX *info = &nsp_list[i];
+
+			if (!g_strcmp0 (nm_wimax_nsp_get_name (nsp), (char *) info->NSPName)) {
+				found = TRUE;
+				break;
+			}
+		}
+
+		if (!found)
+			to_remove = g_slist_prepend (to_remove, nsp);
+	}
+
+	for (iter = to_remove; iter; iter = iter->next) {
+		NMWimaxNsp *nsp = NM_WIMAX_NSP (iter->data);
+
+		emit_nsp_added_removed (self, NSP_REMOVED, nsp, FALSE);
+		priv->nsp_list = g_slist_remove (priv->nsp_list, nsp);
+		g_object_unref (nsp);
+	}
+
+	if (g_slist_length(to_remove) > 0)
+	    nm_device_recheck_available_connections (NM_DEVICE (self));
+
+	g_slist_free (to_remove);
+}
+
+static void
+wmx_scan_result_cb (struct wmxsdk *wmxsdk,
+                    WIMAX_API_NSP_INFO_EX *nsps,
+                    guint num_nsps,
+                    void *user_data)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+	const char *iface = nm_device_get_iface (NM_DEVICE (self));
+	int i;
+
+	remove_outdated_nsps (self, nsps, num_nsps);
+
+	/* Add new NSPs and update existing ones */
+	for (i = 0; i < num_nsps; i++) {
+		WIMAX_API_NSP_INFO_EX *sdk_nsp = &nsps[i];
+		const char *nsp_name = (const char *) sdk_nsp->NSPName;
+		NMWimaxNspNetworkType net_type;
+		guint signalq;
+		NMWimaxNsp *nsp;
+		gboolean new_nsp;
+
+		nsp = get_nsp_by_name (self, nsp_name);
+		new_nsp = (nsp == NULL);
+		if (new_nsp) {
+			nsp = nm_wimax_nsp_new (nsp_name);
+			nm_log_dbg (LOGD_WIMAX, "(%s): new WiMAX NSP '%s'", iface, nsp_name);
+		}
+
+		net_type = nm_wimax_util_convert_network_type (sdk_nsp->networkType);
+		if (net_type != nm_wimax_nsp_get_network_type (nsp))
+			g_object_set (nsp, NM_WIMAX_NSP_NETWORK_TYPE, net_type, NULL);
+
+		signalq = CLAMP (sdk_nsp->linkQuality, 0, 100);
+		if (signalq != nm_wimax_nsp_get_signal_quality (nsp))
+			g_object_set (nsp, NM_WIMAX_NSP_SIGNAL_QUALITY, signalq, NULL);
+
+		nm_log_dbg (LOGD_WIMAX, "(%s): WiMAX NSP '%s' quality %d%% type %d",
+			        iface, nsp_name, sdk_nsp->linkQuality, net_type);
+
+		if (new_nsp) {
+			priv->nsp_list = g_slist_append (priv->nsp_list, nsp);
+			nm_wimax_nsp_export_to_dbus (nsp);
+			emit_nsp_added_removed (self, NSP_ADDED, nsp, TRUE);
+		}
+	}
+}
+
+static void
+wmx_removed_cb (struct wmxsdk *wmxsdk, void *user_data)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+
+	if (!priv->sdk) {
+		nm_log_dbg (LOGD_WIMAX, "(%s): removed unhandled WiMAX interface", wmxsdk->ifname);
+		return;
+	}
+
+	nm_log_dbg (LOGD_WIMAX, "(%s): removed WiMAX interface", wmxsdk->ifname);
+
+	/* Clear callbacks just in case we don't hold the last reference */
+	iwmx_sdk_set_callbacks (priv->sdk, NULL, NULL, NULL, NULL, NULL, NULL);
+	wmxsdk_unref (priv->sdk);
+	priv->sdk = NULL;
+
+	priv->status = WIMAX_API_DEVICE_STATUS_UnInitialized;
+	nm_device_state_changed (NM_DEVICE (self),
+							 NM_DEVICE_STATE_UNAVAILABLE,
+							 NM_DEVICE_STATE_REASON_NONE);
+}
+
+/*************************************************************************/
+
+static inline gint
+sdk_rssi_to_dbm (guint raw_rssi)
+{
+	/* Values range from 0x00 to 0x53, where -123dBm is encoded as 0x00 and
+	 * -40dBm encoded as 0x53 in 1dB increments.
+	 */
+	return raw_rssi - 123;
+}
+
+static inline gint
+sdk_cinr_to_db (guint raw_cinr)
+{
+	/* Values range from 0x00 to 0x3F, where -10dB is encoded as 0x00 and
+	 * 53dB encoded as 0x3F in 1dB increments.
+	 */
+	return raw_cinr - 10;
+}
+
+static inline gint
+sdk_tx_pow_to_dbm (guint raw_tx_pow)
+{
+	/* Values range from 0x00 to 0xFF, where -84dBm is encoded as 0x00 and
+	 * 43.5dBm is encoded as 0xFF in 0.5dB increments.  Normalize so that
+	 * 0 dBm == 0.
+	 */
+	return (int) (((double) raw_tx_pow / 2.0) - 84) * 2;
+}
+
+static void
+set_link_status (NMDeviceWimax *self, WIMAX_API_LINK_STATUS_INFO_EX *link_status)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+	guint center_freq = 0;
+	gint conv_rssi = 0, conv_cinr = 0, conv_tx_pow = 0;
+	char *new_bsid = NULL;
+
+	if (link_status) {
+		center_freq = link_status->centerFrequency;
+		conv_rssi = sdk_rssi_to_dbm (link_status->RSSI);
+		conv_cinr = sdk_cinr_to_db (link_status->CINR);
+		conv_tx_pow = sdk_tx_pow_to_dbm (link_status->txPWR);
+		new_bsid = nm_utils_hwaddr_ntoa_len (link_status->bsId, 6);
+	}
+
+	if (priv->center_freq != center_freq) {
+		priv->center_freq = center_freq;
+		g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_CENTER_FREQUENCY);
+	}
+
+	if (priv->rssi != conv_rssi) {
+		priv->rssi = conv_rssi;
+		g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_RSSI);
+	}
+
+	if (priv->cinr != conv_cinr) {
+		priv->cinr = conv_cinr;
+		g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_CINR);
+	}
+
+	if (priv->tx_power != conv_tx_pow) {
+		priv->tx_power = conv_tx_pow;
+		g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_TX_POWER);
+	}
+
+	if (g_strcmp0 (priv->bsid, new_bsid) != 0) {
+		g_free (priv->bsid);
+		priv->bsid = new_bsid;
+		g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_BSID);
+	} else
+		g_free (new_bsid);
+}
+
+static gboolean
+connected_poll_cb (gpointer user_data)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+	WIMAX_API_CONNECTED_NSP_INFO_EX *sdk_nsp;
+	WIMAX_API_LINK_STATUS_INFO_EX *link_status;
+
+	g_return_val_if_fail (priv->sdk != NULL, FALSE);
+
+	/* Get details of the connected NSP */
+	sdk_nsp = iwmx_sdk_get_connected_network (priv->sdk);
+	if (sdk_nsp) {
+		const char *nsp_name = (const char *) sdk_nsp->NSPName;
+		NMWimaxNsp *nsp;
+
+		nsp = get_nsp_by_name (self, nsp_name);
+		if (nsp) {
+			NMWimaxNspNetworkType net_type;
+			guint signalq;
+
+			net_type = nm_wimax_util_convert_network_type (sdk_nsp->networkType);
+			if (net_type != nm_wimax_nsp_get_network_type (nsp))
+				g_object_set (nsp, NM_WIMAX_NSP_NETWORK_TYPE, net_type, NULL);
+
+			signalq = sdk_nsp->linkQuality;
+			if (signalq != nm_wimax_nsp_get_signal_quality (nsp))
+				g_object_set (nsp, NM_WIMAX_NSP_SIGNAL_QUALITY, signalq, NULL);
+
+			nm_log_dbg (LOGD_WIMAX, "(%s): WiMAX NSP '%s' quality %d%% type %d",
+					    nm_device_get_iface (NM_DEVICE (self)),
+					    nsp_name, sdk_nsp->linkQuality, net_type);
+		}
+		free (sdk_nsp);
+	}
+
+	/* Get details of the current radio link */
+	link_status = iwmx_sdk_get_link_status_info (priv->sdk);
+	if (link_status) {
+		set_link_status (self, link_status);
+		free (link_status);
+	}
+
+	return TRUE; /* reschedule */
+}
+
+static void
+device_state_changed (NMDevice *device,
+                      NMDeviceState new_state,
+                      NMDeviceState old_state,
+                      NMDeviceStateReason reason)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (device);
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+
+	/* Reset our stage1 (Prepare) done marker since it's only valid while in stage1 */
+	priv->prepare_done = FALSE;
+
+	if (new_state < NM_DEVICE_STATE_DISCONNECTED)
+		remove_all_nsps (self);
+
+	/* Request initial NSP list when device is first started */
+	if (   new_state == NM_DEVICE_STATE_DISCONNECTED
+	    && old_state < NM_DEVICE_STATE_DISCONNECTED) {
+		if (priv->sdk)
+			iwmx_sdk_get_networks (priv->sdk);
+	}
+
+	if (new_state == NM_DEVICE_STATE_FAILED || new_state <= NM_DEVICE_STATE_DISCONNECTED) {
+		set_current_nsp (self, NULL);
+		clear_activation_timeout (self);
+	}
+
+	if (new_state == NM_DEVICE_STATE_ACTIVATED) {
+		/* poll link quality and BSID */
+		clear_connected_poll (self);
+		priv->poll_id = g_timeout_add_seconds (10, connected_poll_cb, self);
+		connected_poll_cb (self);
+	} else {
+		clear_link_timeout (self);
+		clear_connected_poll (self);
+		set_link_status (self, NULL);
+	}
+}
+
+/*************************************************************************/
+
+static gboolean
+sdk_action_defer_cb (gpointer user_data)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
+	gboolean old_available = nm_device_is_available (NM_DEVICE (self));
+
+	NM_DEVICE_WIMAX_GET_PRIVATE (self)->sdk_action_defer_id = 0;
+	update_availability (self, old_available);
+	return FALSE;
+}
+
+static void
+wmx_new_sdk_cb (struct wmxsdk *sdk, void *user_data)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+
+	/* We only track one wmxsdk at a time because the WiMAX SDK is pretty stupid */
+	if (priv->sdk) {
+		nm_log_dbg (LOGD_WIMAX, "(%s): WiMAX interface already known", sdk->ifname);
+		return;
+	}
+
+	nm_log_dbg (LOGD_WIMAX, "(%s): new WiMAX interface (%s)", sdk->ifname, sdk->name);
+
+	/* Now that we have an SDK, schedule an idle handler to start the device up */
+	priv->sdk = wmxsdk_ref (sdk);
+	iwmx_sdk_set_callbacks(priv->sdk,
+	                       wmx_state_change_cb,
+	                       wmx_media_status_cb,
+	                       wmx_connect_result_cb,
+	                       wmx_scan_result_cb,
+	                       wmx_removed_cb,
+	                       self);
+	iwmx_sdk_set_fast_reconnect_enabled (priv->sdk, 0);
+
+	if (!priv->sdk_action_defer_id)
+		priv->sdk_action_defer_id = g_idle_add (sdk_action_defer_cb, self);
+}
+
+/*************************************************************************/
+
+NMDevice *
+nm_device_wimax_new (NMPlatformLink *platform_device)
+{
+	NMDevice *device;
+
+	g_return_val_if_fail (platform_device != NULL, NULL);
+
+	device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_WIMAX,
+	                                    NM_DEVICE_PLATFORM_DEVICE, platform_device,
+	                                    NM_DEVICE_TYPE_DESC, "WiMAX",
+	                                    NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_WIMAX,
+	                                    NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WIMAX,
+	                                    NULL);
+	if (device) {
+		struct wmxsdk *sdk;
+
+		nm_wimax_util_sdk_ref ();
+
+		/* See if the SDK already knows about this interface */
+		sdk = iwmx_sdk_get_wmxsdk_for_iface (platform_device->name);
+		if (sdk)
+			wmx_new_sdk_cb (sdk, device);
+
+		/* If it doesn't, we want to be notified when it does */
+		iwmx_sdk_new_callback_register (wmx_new_sdk_cb, device);
+	}
+
+	return device;
+}
+
+static void
+nm_device_wimax_init (NMDeviceWimax *self)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+
+	priv->status = WIMAX_API_DEVICE_STATUS_UnInitialized;
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (object);
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+	GPtrArray *array;
+	GSList *iter;
+
+	switch (prop_id) {
+	case PROP_NSPS:
+		array = g_ptr_array_sized_new (4);
+		for (iter = priv->nsp_list; iter; iter = g_slist_next (iter))
+			g_ptr_array_add (array, g_strdup (nm_wimax_nsp_get_dbus_path (NM_WIMAX_NSP (iter->data))));
+		g_value_take_boxed (value, array);
+		break;
+	case PROP_ACTIVE_NSP:
+		if (priv->current_nsp)
+			g_value_set_boxed (value, nm_wimax_nsp_get_dbus_path (priv->current_nsp));
+		else
+			g_value_set_boxed (value, "/");
+		break;
+	case PROP_CENTER_FREQ:
+		g_value_set_uint (value, priv->center_freq);
+		break;
+	case PROP_RSSI:
+		g_value_set_int (value, priv->rssi);
+		break;
+	case PROP_CINR:
+		g_value_set_int (value, priv->cinr);
+		break;
+	case PROP_TX_POWER:
+		g_value_set_int (value, priv->tx_power);
+		break;
+	case PROP_BSID:
+		g_value_set_string (value, priv->bsid);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+dispose (GObject *object)
+{
+	NMDeviceWimax *self = NM_DEVICE_WIMAX (object);
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
+
+	if (priv->disposed)
+		goto done;
+
+	priv->disposed = TRUE;
+
+	clear_activation_timeout (self);
+	clear_link_timeout (self);
+	clear_connected_poll (self);
+
+	if (priv->sdk_action_defer_id)
+		g_source_remove (priv->sdk_action_defer_id);
+
+	if (priv->sdk) {
+		iwmx_sdk_set_callbacks (priv->sdk, NULL, NULL, NULL, NULL, NULL, NULL);
+		wmxsdk_unref (priv->sdk);
+	}
+
+	g_free (priv->bsid);
+
+	set_current_nsp (self, NULL);
+
+	g_slist_free_full (priv->nsp_list, g_object_unref);
+
+	iwmx_sdk_new_callback_unregister (wmx_new_sdk_cb, self);
+	nm_wimax_util_sdk_unref ();
+
+done:
+	G_OBJECT_CLASS (nm_device_wimax_parent_class)->dispose (object);
+}
+
+static void
+nm_device_wimax_class_init (NMDeviceWimaxClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
+
+	g_type_class_add_private (object_class, sizeof (NMDeviceWimaxPrivate));
+
+	/* Virtual methods */
+	object_class->set_property = set_property;
+	object_class->get_property = get_property;
+	object_class->dispose = dispose;
+
+	device_class->check_connection_compatible = check_connection_compatible;
+	device_class->check_connection_available = check_connection_available;
+	device_class->complete_connection = complete_connection;
+	device_class->can_auto_connect = can_auto_connect;
+	device_class->is_available = is_available;
+	device_class->act_stage1_prepare = act_stage1_prepare;
+	device_class->act_stage2_config = act_stage2_config;
+	device_class->deactivate = deactivate;
+	device_class->set_enabled = set_enabled;
+
+	device_class->state_changed = device_state_changed;
+
+	/* Properties */
+	g_object_class_install_property
+		(object_class, PROP_NSPS,
+		 g_param_spec_boxed (NM_DEVICE_WIMAX_NSPS,
+		                     "Network access points",
+		                     "Network access points",
+		                     DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH,
+		                     G_PARAM_READABLE));
+
+	g_object_class_install_property (object_class, PROP_ACTIVE_NSP,
+		g_param_spec_boxed (NM_DEVICE_WIMAX_ACTIVE_NSP,
+		                    "Active NSP",
+		                    "Currently active NSP",
+		                    DBUS_TYPE_G_OBJECT_PATH,
+		                    G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_CENTER_FREQ,
+		 g_param_spec_uint (NM_DEVICE_WIMAX_CENTER_FREQUENCY,
+		                    "Center frequency",
+		                    "Center frequency",
+		                    0, G_MAXUINT, 0,
+		                    G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_RSSI,
+		 g_param_spec_int (NM_DEVICE_WIMAX_RSSI,
+		                   "RSSI",
+		                   "RSSI",
+		                   G_MININT, G_MAXINT, 0,
+		                   G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_CINR,
+		 g_param_spec_int (NM_DEVICE_WIMAX_CINR,
+		                   "CINR",
+		                   "CINR",
+		                   G_MININT, G_MAXINT, 0,
+		                   G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_TX_POWER,
+		 g_param_spec_int (NM_DEVICE_WIMAX_TX_POWER,
+		                   "TX Power",
+		                   "TX Power",
+		                   G_MININT, G_MAXINT, 0,
+		                   G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_BSID,
+		 g_param_spec_string (NM_DEVICE_WIMAX_BSID,
+		                      "BSID",
+		                      "BSID",
+		                      NULL,
+		                      G_PARAM_READABLE));
+
+	/* Signals */
+	signals[NSP_ADDED] =
+		g_signal_new ("nsp-added",
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (NMDeviceWimaxClass, nsp_added),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__OBJECT,
+					  G_TYPE_NONE, 1,
+					  G_TYPE_OBJECT);
+
+	signals[NSP_REMOVED] =
+		g_signal_new ("nsp-removed",
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (NMDeviceWimaxClass, nsp_removed),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__OBJECT,
+					  G_TYPE_NONE, 1,
+					  G_TYPE_OBJECT);
+
+	nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
+	                                        G_TYPE_FROM_CLASS (klass),
+	                                        &dbus_glib_nm_device_wimax_object_info);
+
+	dbus_g_error_domain_register (NM_WIMAX_ERROR, NULL, NM_TYPE_WIMAX_ERROR);
+}
diff --git a/src/devices/wimax/nm-device-wimax.h b/src/devices/wimax/nm-device-wimax.h
new file mode 100644
index 00000000..8b252ee1
--- /dev/null
+++ b/src/devices/wimax/nm-device-wimax.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2010 - 2011 Red Hat, Inc.
+ * Copyright (C) 2009 Novell, Inc.
+ */
+
+#ifndef NM_DEVICE_WIMAX_H
+#define NM_DEVICE_WIMAX_H
+
+#include <net/ethernet.h>
+#include "nm-device.h"
+#include "nm-wimax-nsp.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_WIMAX            (nm_device_wimax_get_type ())
+#define NM_DEVICE_WIMAX(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_WIMAX, NMDeviceWimax))
+#define NM_DEVICE_WIMAX_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_DEVICE_WIMAX, NMDeviceWimaxClass))
+#define NM_IS_DEVICE_WIMAX(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_WIMAX))
+#define NM_IS_DEVICE_WIMAX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE_WIMAX))
+#define NM_DEVICE_WIMAX_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE_WIMAX, NMDeviceWimaxClass))
+
+typedef enum
+{
+	NM_WIMAX_ERROR_CONNECTION_NOT_WIMAX = 0, /*< nick=ConnectionNotWimax >*/
+	NM_WIMAX_ERROR_CONNECTION_INVALID,       /*< nick=ConnectionInvalid >*/
+	NM_WIMAX_ERROR_CONNECTION_INCOMPATIBLE,  /*< nick=ConnectionIncompatible >*/
+	NM_WIMAX_ERROR_NSP_NOT_FOUND,            /*< nick=NspNotFound >*/
+} NMWimaxError;
+
+#define NM_DEVICE_WIMAX_NSPS             "nsps"
+#define NM_DEVICE_WIMAX_ACTIVE_NSP       "active-nsp"
+#define NM_DEVICE_WIMAX_CENTER_FREQUENCY "center-frequency"
+#define NM_DEVICE_WIMAX_RSSI             "rssi"
+#define NM_DEVICE_WIMAX_CINR             "cinr"
+#define NM_DEVICE_WIMAX_TX_POWER         "tx-power"
+#define NM_DEVICE_WIMAX_BSID             "bsid"
+
+typedef struct {
+	NMDevice parent;
+} NMDeviceWimax;
+
+typedef struct {
+	NMDeviceClass parent;
+
+	/* Signals */
+	void (*nsp_added)   (NMDeviceWimax *wimax, NMWimaxNsp *nsp);
+	void (*nsp_removed) (NMDeviceWimax *wimax, NMWimaxNsp *nsp);
+	void (*properties_changed) (NMDeviceWimax *wimax, GHashTable *properties);
+} NMDeviceWimaxClass;
+
+GType nm_device_wimax_get_type (void);
+
+NMDevice   *nm_device_wimax_new            (NMPlatformLink *platform_device);
+
+G_END_DECLS
+
+#endif	/* NM_DEVICE_WIMAX_H */
diff --git a/src/devices/wimax/nm-wimax-factory.c b/src/devices/wimax/nm-wimax-factory.c
new file mode 100644
index 00000000..ca962e68
--- /dev/null
+++ b/src/devices/wimax/nm-wimax-factory.c
@@ -0,0 +1,89 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2011 - 2014 Red Hat, Inc.
+ */
+
+#include <gmodule.h>
+
+#include "nm-device-factory.h"
+#include "nm-device-wimax.h"
+
+#define NM_TYPE_WIMAX_FACTORY            (nm_wimax_factory_get_type ())
+#define NM_WIMAX_FACTORY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_WIMAX_FACTORY, NMWimaxFactory))
+
+typedef struct {
+	GObject parent;
+} NMWimaxFactory;
+
+typedef struct {
+	GObjectClass parent;
+} NMWimaxFactoryClass;
+
+static GType nm_wimax_factory_get_type (void);
+
+static void device_factory_interface_init (NMDeviceFactory *factory_iface);
+
+G_DEFINE_TYPE_EXTENDED (NMWimaxFactory, nm_wimax_factory, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_FACTORY, device_factory_interface_init))
+
+/**************************************************************************/
+
+#define PLUGIN_TYPE NM_DEVICE_TYPE_WIMAX
+
+G_MODULE_EXPORT NMDeviceFactory *
+nm_device_factory_create (GError **error)
+{
+	return (NMDeviceFactory *) g_object_new (NM_TYPE_WIMAX_FACTORY, NULL);
+}
+
+G_MODULE_EXPORT NMDeviceType
+nm_device_factory_get_device_type (void)
+{
+	return PLUGIN_TYPE;
+}
+
+/**************************************************************************/
+
+static NMDevice *
+new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
+{
+	/* FIXME: check udev 'DEVTYPE' instead; but since we only support Intel
+	 * WiMAX devices for now this is appropriate.
+	 */
+	if (g_strcmp0 (plink->driver, "i2400m_usb") != 0)
+		return NULL;  /* unsupported */
+
+	return (NMDevice *) nm_device_wimax_new (plink);
+}
+
+static void
+device_factory_interface_init (NMDeviceFactory *factory_iface)
+{
+	factory_iface->new_link = new_link;
+}
+
+static void
+nm_wimax_factory_init (NMWimaxFactory *factory)
+{
+}
+
+static void
+nm_wimax_factory_class_init (NMWimaxFactoryClass *wf_class)
+{
+}
+
diff --git a/src/devices/wimax/nm-wimax-nsp.c b/src/devices/wimax/nm-wimax-nsp.c
new file mode 100644
index 00000000..efe3b058
--- /dev/null
+++ b/src/devices/wimax/nm-wimax-nsp.c
@@ -0,0 +1,242 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2010 - 2012 Red Hat, Inc.
+ * Copyright (C) 2009 Novell, Inc.
+ */
+
+#include "nm-wimax-nsp.h"
+#include "NetworkManager.h"
+#include "nm-dbus-manager.h"
+#include "nm-setting-wimax.h"
+#include "nm-wimax-nsp-glue.h"
+#include "nm-utils.h"
+
+G_DEFINE_TYPE (NMWimaxNsp, nm_wimax_nsp, G_TYPE_OBJECT)
+
+enum {
+	PROP_0,
+
+	PROP_NAME,
+	PROP_SIGNAL_QUALITY,
+	PROP_NETWORK_TYPE,
+
+	LAST_PROP
+};
+
+#define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_WIMAX_NSP, NMWimaxNspPrivate))
+
+typedef struct {
+	char *dbus_path;
+
+	char *name;
+	guint32 signal_quality;
+	NMWimaxNspNetworkType network_type;
+} NMWimaxNspPrivate;
+
+NMWimaxNsp *
+nm_wimax_nsp_new (const char *name)
+{
+	g_return_val_if_fail (name != NULL, NULL);
+
+	return NM_WIMAX_NSP (g_object_new (NM_TYPE_WIMAX_NSP,
+									   NM_WIMAX_NSP_NAME, name,
+									   NULL));
+}
+
+const char *
+nm_wimax_nsp_get_name (NMWimaxNsp *self)
+{
+	g_return_val_if_fail (NM_IS_WIMAX_NSP (self), NULL);
+
+	return GET_PRIVATE (self)->name;
+}
+
+guint32
+nm_wimax_nsp_get_signal_quality (NMWimaxNsp *self)
+{
+	g_return_val_if_fail (NM_IS_WIMAX_NSP (self), 0);
+
+	return GET_PRIVATE (self)->signal_quality;
+}
+
+NMWimaxNspNetworkType
+nm_wimax_nsp_get_network_type (NMWimaxNsp *self)
+{
+	g_return_val_if_fail (NM_IS_WIMAX_NSP (self), 0);
+
+	return GET_PRIVATE (self)->network_type;
+}
+
+void
+nm_wimax_nsp_export_to_dbus (NMWimaxNsp *self)
+{
+	NMWimaxNspPrivate *priv;
+	static guint32 counter = 0;
+
+	g_return_if_fail (NM_IS_WIMAX_NSP (self));
+
+	priv = GET_PRIVATE (self);
+
+	g_return_if_fail (priv->dbus_path == NULL);
+
+	priv->dbus_path = g_strdup_printf (NM_DBUS_PATH_WIMAX_NSP "/%d", counter++);
+	nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->dbus_path, self);
+}
+
+const char *
+nm_wimax_nsp_get_dbus_path (NMWimaxNsp *self)
+{
+	g_return_val_if_fail (NM_IS_WIMAX_NSP (self), NULL);
+
+	return GET_PRIVATE (self)->dbus_path;
+}
+
+gboolean
+nm_wimax_nsp_check_compatible (NMWimaxNsp *self,
+							   NMConnection *connection)
+{
+	NMWimaxNspPrivate *priv;
+	NMSettingWimax *s_wimax;
+
+	g_return_val_if_fail (NM_IS_WIMAX_NSP (self), FALSE);
+	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+
+	priv = GET_PRIVATE (self);
+
+	s_wimax = nm_connection_get_setting_wimax (connection);
+	if (!s_wimax)
+		return FALSE;
+
+	return g_strcmp0 (nm_wimax_nsp_get_name (self), nm_setting_wimax_get_network_name (s_wimax)) == 0;
+}
+
+static void
+nm_wimax_nsp_init (NMWimaxNsp *self)
+{
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+	NMWimaxNspPrivate *priv = GET_PRIVATE (object);
+	guint32 quality;
+	guint network_type;
+
+	switch (prop_id) {
+	case PROP_NAME:
+		/* Construct only */
+		priv->name = g_value_dup_string (value);
+		break;
+	case PROP_SIGNAL_QUALITY:
+		quality = g_value_get_uint (value);
+		if (quality != priv->signal_quality) {
+			priv->signal_quality = CLAMP (quality, 0, 100);
+			g_object_notify (object, NM_WIMAX_NSP_SIGNAL_QUALITY);
+		}
+		break;
+	case PROP_NETWORK_TYPE:
+		network_type = g_value_get_uint (value);
+		if (network_type != priv->network_type) {
+			priv->network_type = network_type;
+			g_object_notify (object, NM_WIMAX_NSP_NETWORK_TYPE);
+		}
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
+{
+	NMWimaxNsp *self = NM_WIMAX_NSP (object);
+
+	switch (prop_id) {
+	case PROP_NAME:
+		g_value_set_string (value, nm_wimax_nsp_get_name (self));
+		break;
+	case PROP_SIGNAL_QUALITY:
+		g_value_set_uint (value, nm_wimax_nsp_get_signal_quality (self));
+		break;
+	case PROP_NETWORK_TYPE:
+		g_value_set_uint (value, nm_wimax_nsp_get_network_type (self));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+finalize (GObject *object)
+{
+	NMWimaxNspPrivate *priv = GET_PRIVATE (object);
+
+	g_free (priv->name);
+	g_free (priv->dbus_path);
+
+	G_OBJECT_CLASS (nm_wimax_nsp_parent_class)->finalize (object);
+}
+
+static void
+nm_wimax_nsp_class_init (NMWimaxNspClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (object_class, sizeof (NMWimaxNspPrivate));
+
+	/* Virtual methods */
+	object_class->set_property = set_property;
+	object_class->get_property = get_property;
+	object_class->finalize = finalize;
+
+	g_object_class_install_property
+		(object_class, PROP_NAME,
+		 g_param_spec_string (NM_WIMAX_NSP_NAME,
+							  "Name",
+							  "Name",
+							  NULL,
+							  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property
+		(object_class, PROP_SIGNAL_QUALITY,
+		 g_param_spec_uint (NM_WIMAX_NSP_SIGNAL_QUALITY,
+							"SignalQuality",
+							"SignalQuality",
+							0,
+							100,
+							0,
+							G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_NETWORK_TYPE,
+		 g_param_spec_uint (NM_WIMAX_NSP_NETWORK_TYPE,
+		                    "NetworkType",
+		                    "NetworkType",
+		                    NM_WIMAX_NSP_NETWORK_TYPE_UNKNOWN,
+		                    NM_WIMAX_NSP_NETWORK_TYPE_ROAMING_PARTNER,
+		                    NM_WIMAX_NSP_NETWORK_TYPE_UNKNOWN,
+		                    G_PARAM_READWRITE));
+
+	nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
+	                                        G_TYPE_FROM_CLASS (klass),
+	                                        &dbus_glib_nm_wimax_nsp_object_info);
+}
diff --git a/src/devices/wimax/nm-wimax-nsp.h b/src/devices/wimax/nm-wimax-nsp.h
new file mode 100644
index 00000000..a74b68a7
--- /dev/null
+++ b/src/devices/wimax/nm-wimax-nsp.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2009 Novell, Inc.
+ */
+
+#ifndef NM_WIMAX_NSP_H
+#define NM_WIMAX_NSP_H
+
+#include <glib-object.h>
+#include "nm-wimax-types.h"
+#include "nm-connection.h"
+
+#define NM_TYPE_WIMAX_NSP			(nm_wimax_nsp_get_type ())
+#define NM_WIMAX_NSP(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WIMAX_NSP, NMWimaxNsp))
+#define NM_WIMAX_NSP_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_WIMAX_NSP, NMWimaxNspClass))
+#define NM_IS_WIMAX_NSP(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_WIMAX_NSP))
+#define NM_IS_WIMAX_NSP_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_WIMAX_NSP))
+#define NM_WIMAX_NSP_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_WIMAX_NSP, NMWimaxNspClass))
+
+#define NM_WIMAX_NSP_NAME           "name"
+#define NM_WIMAX_NSP_SIGNAL_QUALITY "signal-quality"
+#define NM_WIMAX_NSP_NETWORK_TYPE   "network-type"
+
+typedef struct {
+	GObject parent;
+} NMWimaxNsp;
+
+typedef struct {
+	GObjectClass parent;
+
+	/* Signals */
+	void (*properties_changed) (NMWimaxNsp *nsp, GHashTable *properties);
+} NMWimaxNspClass;
+
+GType nm_wimax_nsp_get_type (void);
+
+NMWimaxNsp            *nm_wimax_nsp_new                (const char *name);
+const char            *nm_wimax_nsp_get_name           (NMWimaxNsp *self);
+guint32                nm_wimax_nsp_get_signal_quality (NMWimaxNsp *self);
+NMWimaxNspNetworkType  nm_wimax_nsp_get_network_type   (NMWimaxNsp *self);
+
+void                   nm_wimax_nsp_export_to_dbus     (NMWimaxNsp *self);
+const char            *nm_wimax_nsp_get_dbus_path      (NMWimaxNsp *self);
+
+gboolean               nm_wimax_nsp_check_compatible   (NMWimaxNsp *self,
+														NMConnection *connection);
+
+#endif	/* NM_WIMAX_NSP_H */
diff --git a/src/devices/wimax/nm-wimax-types.h b/src/devices/wimax/nm-wimax-types.h
new file mode 100644
index 00000000..8c807fd8
--- /dev/null
+++ b/src/devices/wimax/nm-wimax-types.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2009 Novell, Inc.
+ */
+
+#ifndef NM_WIMAX_TYPES_H
+#define NM_WIMAX_TYPES_H
+
+typedef enum {
+	NM_WIMAX_NSP_NETWORK_TYPE_UNKNOWN,
+	NM_WIMAX_NSP_NETWORK_TYPE_HOME,
+	NM_WIMAX_NSP_NETWORK_TYPE_PARTNER,
+	NM_WIMAX_NSP_NETWORK_TYPE_ROAMING_PARTNER
+} NMWimaxNspNetworkType;
+
+#endif	/* NM_WIMAX_TYPES_H */
diff --git a/src/devices/wimax/nm-wimax-util.c b/src/devices/wimax/nm-wimax-util.c
new file mode 100644
index 00000000..bca25a1d
--- /dev/null
+++ b/src/devices/wimax/nm-wimax-util.c
@@ -0,0 +1,82 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2009 Novell, Inc.
+ */
+
+#include <WiMaxAPI.h>
+#include "nm-wimax-util.h"
+#include "nm-utils.h"
+#include "iwmxsdk.h"
+#include "nm-logging.h"
+
+static guint sdk_refcount = 0;
+
+void
+nm_wimax_util_sdk_ref (void)
+{
+	int ret = 0;
+
+	if (sdk_refcount == 0) {
+		ret = iwmx_sdk_api_init ();
+		if (ret != 0) {
+			nm_log_warn (LOGD_WIMAX, "Failed to initialize WiMAX: %d", ret);
+			return;
+		}
+	}
+	sdk_refcount++;
+}
+
+gboolean
+nm_wimax_util_sdk_is_initialized (void)
+{
+	return sdk_refcount > 0;
+}
+
+void
+nm_wimax_util_sdk_unref (void)
+{
+	g_return_if_fail (sdk_refcount > 0);
+
+	sdk_refcount--;
+	if (sdk_refcount == 0)
+		iwmx_sdk_api_exit ();
+}
+
+NMWimaxNspNetworkType
+nm_wimax_util_convert_network_type (WIMAX_API_NETWORK_TYPE wimax_network_type)
+{
+	NMWimaxNspNetworkType type;
+
+	switch (wimax_network_type) {
+	case WIMAX_API_HOME:
+		type = NM_WIMAX_NSP_NETWORK_TYPE_HOME;
+		break;
+	case WIMAX_API_PARTNER:
+		type = NM_WIMAX_NSP_NETWORK_TYPE_PARTNER;
+		break;
+	case WIMAX_API_ROAMING_PARTNER:
+		type = NM_WIMAX_NSP_NETWORK_TYPE_ROAMING_PARTNER;
+		break;
+	default:
+		type = NM_WIMAX_NSP_NETWORK_TYPE_UNKNOWN;
+		break;
+	}
+
+	return type;
+}
+
diff --git a/src/devices/wimax/nm-wimax-util.h b/src/devices/wimax/nm-wimax-util.h
new file mode 100644
index 00000000..71f5aa29
--- /dev/null
+++ b/src/devices/wimax/nm-wimax-util.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2009 Novell, Inc.
+ */
+
+#ifndef NM_WIMAX_UTIL_H
+#define NM_WIMAX_UTIL_H
+
+#include <glib.h>
+
+#include <WiMaxType.h>
+#include <WiMaxError.h>
+#include "nm-wimax-types.h"
+
+void nm_wimax_util_sdk_ref (void);
+
+gboolean nm_wimax_util_sdk_is_initialized (void);
+
+void nm_wimax_util_sdk_unref (void);
+
+NMWimaxNspNetworkType nm_wimax_util_convert_network_type (WIMAX_API_NETWORK_TYPE wimax_network_type);
+
+#endif	/* NM_WIMAX_UTIL_H */