diff options
| author | Michael Biebl <biebl@debian.org> | 2014-07-06 02:16:10 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2014-07-06 02:16:10 +0200 |
| commit | 33491bc4279481db8ae47213e34a6d695a0e8830 (patch) | |
| tree | 097d2b0fdff3fae6885381ae5e57a182cd8cbbba /src/platform | |
| parent | 59c3714a494c3b3765657c0551ad82842d98a7d2 (diff) | |
Imported Upstream version 0.9.10.0 upstream/0.9.10.0
Diffstat (limited to 'src/platform')
26 files changed, 15985 insertions, 0 deletions
diff --git a/src/platform/Makefile.am b/src/platform/Makefile.am new file mode 100644 index 00000000..3c6155b9 --- /dev/null +++ b/src/platform/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = tests diff --git a/src/platform/Makefile.in b/src/platform/Makefile.in new file mode 100644 index 00000000..9358879f --- /dev/null +++ b/src/platform/Makefile.in @@ -0,0 +1,753 @@ +# 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/platform +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am +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_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 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +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 +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +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@ +SUBDIRS = tests +all: all-recursive + +.SUFFIXES: +$(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/platform/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/platform/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): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(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-recursive + +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-recursive + +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 + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +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: + +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." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean 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-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-am uninstall uninstall-am + + +# 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/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c new file mode 100644 index 00000000..46272217 --- /dev/null +++ b/src/platform/nm-fake-platform.c @@ -0,0 +1,1352 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-platform-fake.c - Fake platform interaction code for testing NetworkManager + * + * 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, 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) 2012–2013 Red Hat, Inc. + */ + +#include <errno.h> +#include <unistd.h> +#include <netinet/icmp6.h> +#include <netinet/in.h> + +#include "NetworkManagerUtils.h" +#include "nm-fake-platform.h" +#include "nm-logging.h" + +#define debug(format, ...) nm_log_dbg (LOGD_PLATFORM, format, __VA_ARGS__) + +typedef struct { + GHashTable *options; + GArray *links; + GArray *ip4_addresses; + GArray *ip6_addresses; + GArray *ip4_routes; + GArray *ip6_routes; +} NMFakePlatformPrivate; + +typedef struct { + NMPlatformLink link; + + char *udi; + GBytes *address; + int vlan_id; +} NMFakePlatformLink; + +#define NM_FAKE_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_FAKE_PLATFORM, NMFakePlatformPrivate)) + +G_DEFINE_TYPE (NMFakePlatform, nm_fake_platform, NM_TYPE_PLATFORM) + +/******************************************************************/ + +void +nm_fake_platform_setup (void) +{ + nm_platform_setup (NM_TYPE_FAKE_PLATFORM); +} + +/******************************************************************/ + +static gboolean +sysctl_set (NMPlatform *platform, const char *path, const char *value) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + + g_hash_table_insert (priv->options, g_strdup (path), g_strdup (value)); + + return TRUE; +} + +static char * +sysctl_get (NMPlatform *platform, const char *path) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + + return g_strdup (g_hash_table_lookup (priv->options, path)); +} + +static const char * +type_to_type_name (NMLinkType type) +{ + switch (type) { + case NM_LINK_TYPE_UNKNOWN: + return "unknown"; + case NM_LINK_TYPE_LOOPBACK: + return "loopback"; + case NM_LINK_TYPE_ETHERNET: + return "ethernet"; + case NM_LINK_TYPE_DUMMY: + return "dummy"; + case NM_LINK_TYPE_BRIDGE: + return "bridge"; + case NM_LINK_TYPE_BOND: + return "bond"; + case NM_LINK_TYPE_TEAM: + return "team"; + case NM_LINK_TYPE_VLAN: + return "vlan"; + case NM_LINK_TYPE_NONE: + default: + return NULL; + } +} + +static void +link_init (NMFakePlatformLink *device, int ifindex, int type, const char *name) +{ + g_assert (!name || strlen (name) < sizeof(device->link.name)); + + memset (device, 0, sizeof (*device)); + + device->link.ifindex = name ? ifindex : 0; + device->link.type = type; + device->link.type_name = type_to_type_name (type); + device->link.driver = type_to_type_name (type); + device->link.udi = device->udi = g_strdup_printf ("fake:%d", ifindex); + if (name) + strcpy (device->link.name, name); + switch (device->link.type) { + case NM_LINK_TYPE_DUMMY: + device->link.arp = FALSE; + break; + default: + device->link.arp = TRUE; + } + device->address = NULL; +} + +static NMFakePlatformLink * +link_get (NMPlatform *platform, int ifindex) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + NMFakePlatformLink *device; + + if (ifindex >= priv->links->len) + goto not_found; + device = &g_array_index (priv->links, NMFakePlatformLink, ifindex); + if (!device->link.ifindex) + goto not_found; + + return device; +not_found: + debug ("link not found: %d", ifindex); + platform->error = NM_PLATFORM_ERROR_NOT_FOUND; + return NULL; +} + +static GArray * +link_get_all (NMPlatform *platform) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + GArray *links = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformLink), priv->links->len); + int i; + + for (i = 0; i < priv->links->len; i++) + if (g_array_index (priv->links, NMFakePlatformLink, i).link.ifindex) + g_array_append_val (links, g_array_index (priv->links, NMFakePlatformLink, i).link); + + return links; +} + +static gboolean +_nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *link) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (device) + *link = device->link; + return !!device; +} + +static gboolean +link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + NMFakePlatformLink device; + + link_init (&device, priv->links->len, type, name); + + g_array_append_val (priv->links, device); + + if (device.link.ifindex) + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, device.link.ifindex, &device, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); + + return TRUE; +} + +static gboolean +link_delete (NMPlatform *platform, int ifindex) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + NMFakePlatformLink *device = link_get (platform, ifindex); + NMPlatformLink deleted_device; + int i; + + if (!device || !device->link.ifindex) + return FALSE; + + memcpy (&deleted_device, &device->link, sizeof (deleted_device)); + memset (&device->link, 0, sizeof (device->link)); + + /* Remove addresses and routes which belong to the deleted interface */ + for (i = 0; i < priv->ip4_addresses->len; i++) { + NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); + + if (address->ifindex == ifindex) + memset (address, 0, sizeof (*address)); + } + for (i = 0; i < priv->ip6_addresses->len; i++) { + NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i); + + if (address->ifindex == ifindex) + memset (address, 0, sizeof (*address)); + } + for (i = 0; i < priv->ip4_routes->len; i++) { + NMPlatformIP4Route *route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); + + if (route->ifindex == ifindex) + memset (route, 0, sizeof (*route)); + } + for (i = 0; i < priv->ip6_routes->len; i++) { + NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); + + if (route->ifindex == ifindex) + memset (route, 0, sizeof (*route)); + } + + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, ifindex, &deleted_device, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_INTERNAL); + + return TRUE; +} + +static int +link_get_ifindex (NMPlatform *platform, const char *name) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + int i; + + for (i = 0; i < priv->links->len; i++) { + NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i); + + if (device && !g_strcmp0 (device->link.name, name)) + return device->link.ifindex; + } + + return 0; +} + +static const char * +link_get_name (NMPlatform *platform, int ifindex) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + return device ? device->link.name : NULL; +} + +static NMLinkType +link_get_type (NMPlatform *platform, int ifindex) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + return device ? device->link.type : NM_LINK_TYPE_NONE; +} + +static const char * +link_get_type_name (NMPlatform *platform, int ifindex) +{ + return type_to_type_name (link_get_type (platform, ifindex)); +} + +static void +link_changed (NMPlatform *platform, NMFakePlatformLink *device) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + int i; + + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, device->link.ifindex, &device->link, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); + + if (device->link.master) { + NMFakePlatformLink *master = link_get (platform, device->link.master); + + g_return_if_fail (master != device); + + master->link.connected = FALSE; + for (i = 0; i < priv->links->len; i++) { + NMFakePlatformLink *slave = &g_array_index (priv->links, NMFakePlatformLink, i); + + if (slave && slave->link.master == master->link.ifindex && slave->link.connected) + master->link.connected = TRUE; + } + + link_changed (platform, master); + } +} + +static gboolean +link_set_up (NMPlatform *platform, int ifindex) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (!device) + return FALSE; + + device->link.up = TRUE; + switch (device->link.type) { + case NM_LINK_TYPE_DUMMY: + case NM_LINK_TYPE_VLAN: + device->link.connected = TRUE; + break; + case NM_LINK_TYPE_BRIDGE: + case NM_LINK_TYPE_BOND: + case NM_LINK_TYPE_TEAM: + device->link.connected = FALSE; + break; + default: + device->link.connected = FALSE; + g_error ("Unexpected device type: %d", device->link.type); + } + + link_changed (platform, device); + + return TRUE; +} + +static gboolean +link_set_down (NMPlatform *platform, int ifindex) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (!device) + return FALSE; + + device->link.up = FALSE; + device->link.connected = FALSE; + + link_changed (platform, device); + + return TRUE; +} + +static gboolean +link_set_arp (NMPlatform *platform, int ifindex) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (!device) + return FALSE; + + device->link.arp = TRUE; + + link_changed (platform, device); + + return TRUE; +} + +static gboolean +link_set_noarp (NMPlatform *platform, int ifindex) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (!device) + return FALSE; + + device->link.arp = FALSE; + + link_changed (platform, device); + + return TRUE; +} + +static gboolean +link_is_up (NMPlatform *platform, int ifindex) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + return device ? device->link.up : FALSE; +} + +static gboolean +link_is_connected (NMPlatform *platform, int ifindex) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + return device ? device->link.connected : FALSE; +} + +static gboolean +link_uses_arp (NMPlatform *platform, int ifindex) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + return device ? device->link.arp : FALSE; +} + +static gboolean +link_set_address (NMPlatform *platform, int ifindex, gconstpointer addr, size_t len) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (device->address) + g_bytes_unref (device->address); + + device->address = g_bytes_new (addr, len); + + link_changed (platform, link_get (platform, ifindex)); + + return TRUE; +} + +static gconstpointer +link_get_address (NMPlatform *platform, int ifindex, size_t *length) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (!device || !device->address) { + if (length) + *length = 0; + return NULL; + } + + return g_bytes_get_data (device->address, length); +} + +static gboolean +link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (device) { + device->link.mtu = mtu; + link_changed (platform, device); + } + + return !!device; +} + +static guint32 +link_get_mtu (NMPlatform *platform, int ifindex) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + return device ? device->link.mtu : 0; +} + +static char * +link_get_physical_port_id (NMPlatform *platform, int ifindex) +{ + /* We call link_get just to cause an error to be set if @ifindex is bad. */ + link_get (platform, ifindex); + + return NULL; +} + +static gboolean +link_get_wake_on_lan (NMPlatform *platform, int ifindex) +{ + /* We call link_get just to cause an error to be set if @ifindex is bad. */ + link_get (platform, ifindex); + + return FALSE; +} + +static gboolean +link_supports_carrier_detect (NMPlatform *platform, int ifindex) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (!device) + return FALSE; + + switch (device->link.type) { + case NM_LINK_TYPE_DUMMY: + return FALSE; + default: + return TRUE; + } +} + +static gboolean +link_supports_vlans (NMPlatform *platform, int ifindex) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (!device) + return FALSE; + + switch (device->link.type) { + case NM_LINK_TYPE_LOOPBACK: + return FALSE; + default: + return TRUE; + } +} + +static gboolean +link_enslave (NMPlatform *platform, int master, int slave) +{ + NMFakePlatformLink *device = link_get (platform, slave); + + g_return_val_if_fail (device, FALSE); + + device->link.master = master; + + link_changed (platform, device); + + return TRUE; +} + +static gboolean +link_release (NMPlatform *platform, int master_idx, int slave_idx) +{ + NMFakePlatformLink *master = link_get (platform, master_idx); + NMFakePlatformLink *slave = link_get (platform, slave_idx); + + g_return_val_if_fail (master, FALSE); + g_return_val_if_fail (slave, FALSE); + + if (slave->link.master != master->link.ifindex) { + platform->error = NM_PLATFORM_ERROR_NOT_SLAVE; + return FALSE; + } + + slave->link.master = 0; + + link_changed (platform, slave); + link_changed (platform, master); + + return TRUE; +} + +static int +link_get_master (NMPlatform *platform, int slave) +{ + NMFakePlatformLink *device = link_get (platform, slave); + + g_return_val_if_fail (device, FALSE); + + return device->link.master; +} + +static gboolean +master_set_option (NMPlatform *platform, int master, const char *option, const char *value) +{ + auto_g_free char *path = g_strdup_printf ("master:%d:%s", master, option); + + return sysctl_set (platform, path, value); +} + +static char * +master_get_option (NMPlatform *platform, int master, const char *option) +{ + auto_g_free char *path = g_strdup_printf ("master:%d:%s", master, option); + + return sysctl_get (platform, path); +} + +static gboolean +slave_set_option (NMPlatform *platform, int slave, const char *option, const char *value) +{ + auto_g_free char *path = g_strdup_printf ("slave:%d:%s", slave, option); + + return sysctl_set (platform, path, value); +} + +static char * +slave_get_option (NMPlatform *platform, int slave, const char *option) +{ + auto_g_free char *path = g_strdup_printf ("slave:%d:%s", slave, option); + + return sysctl_get (platform, path); +} + +static gboolean +vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags) +{ + NMFakePlatformLink *device; + + if (!link_add (platform, name, NM_LINK_TYPE_VLAN, NULL, 0)) + return FALSE; + + device = link_get (platform, link_get_ifindex (platform, name)); + + g_return_val_if_fail (device, FALSE); + + device->vlan_id = vlan_id; + device->link.parent = parent; + + return TRUE; +} + +static gboolean +vlan_get_info (NMPlatform *platform, int ifindex, int *parent, int *vlan_id) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + g_return_val_if_fail (device, FALSE); + + if (parent) + *parent = device->link.parent; + if (vlan_id) + *vlan_id = device->vlan_id; + + return TRUE; +} + +static gboolean +vlan_set_ingress_map (NMPlatform *platform, int ifindex, int from, int to) +{ + return !!link_get (platform, ifindex); +} + +static gboolean +vlan_set_egress_map (NMPlatform *platform, int ifindex, int from, int to) +{ + return !!link_get (platform, ifindex); +} + +static gboolean +infiniband_partition_add (NMPlatform *platform, int parent, int p_key) +{ + NMFakePlatformLink *parent_device; + char *name; + gboolean success; + + parent_device = link_get (platform, parent); + g_return_val_if_fail (parent_device != NULL, FALSE); + + name = g_strdup_printf ("%s.%04x", parent_device->link.name, p_key); + success = link_add (platform, name, NM_LINK_TYPE_INFINIBAND, NULL, 0); + g_free (name); + + return success; +} + +static gboolean +veth_get_properties (NMPlatform *platform, int ifindex, NMPlatformVethProperties *props) +{ + return FALSE; +} + +static gboolean +tun_get_properties (NMPlatform *platform, int ifindex, NMPlatformTunProperties *props) +{ + return FALSE; +} + +static gboolean +macvlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformMacvlanProperties *props) +{ + return FALSE; +} + +static gboolean +vxlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformVxlanProperties *props) +{ + return FALSE; +} + +static gboolean +gre_get_properties (NMPlatform *platform, int ifindex, NMPlatformGreProperties *props) +{ + return FALSE; +} + +static gboolean +wifi_get_capabilities (NMPlatform *platform, int ifindex, NMDeviceWifiCapabilities *caps) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + g_return_val_if_fail (device, FALSE); + + if (device->link.type != NM_LINK_TYPE_WIFI) + return FALSE; + + if (caps) { + *caps = ( NM_WIFI_DEVICE_CAP_CIPHER_WEP40 + | NM_WIFI_DEVICE_CAP_CIPHER_WEP104 + | NM_WIFI_DEVICE_CAP_CIPHER_TKIP + | NM_WIFI_DEVICE_CAP_CIPHER_CCMP + | NM_WIFI_DEVICE_CAP_WPA + | NM_WIFI_DEVICE_CAP_RSN + | NM_WIFI_DEVICE_CAP_AP + | NM_WIFI_DEVICE_CAP_ADHOC); + } + return TRUE; +} + +static gboolean +wifi_get_bssid (NMPlatform *platform, int ifindex, struct ether_addr *bssid) +{ + return FALSE; +} + +static GByteArray * +wifi_get_ssid (NMPlatform *platform, int ifindex) +{ + return NULL; +} + +static guint32 +wifi_get_frequency (NMPlatform *platform, int ifindex) +{ + return 0; +} + +static int +wifi_get_quality (NMPlatform *platform, int ifindex) +{ + return 0; +} + +static guint32 +wifi_get_rate (NMPlatform *platform, int ifindex) +{ + return 0; +} + +static NM80211Mode +wifi_get_mode (NMPlatform *platform, int ifindex) +{ + return NM_802_11_MODE_UNKNOWN; +} + +static void +wifi_set_mode (NMPlatform *platform, int ifindex, NM80211Mode mode) +{ + ; +} + +static guint32 +wifi_find_frequency (NMPlatform *platform, int ifindex, const guint32 *freqs) +{ + return freqs[0]; +} + +static void +wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean running) +{ + ; +} + +static guint32 +mesh_get_channel (NMPlatform *platform, int ifindex) +{ + return 0; +} + +static gboolean +mesh_set_channel (NMPlatform *platform, int ifindex, guint32 channel) +{ + return FALSE; +} + +static gboolean +mesh_set_ssid (NMPlatform *platform, int ifindex, const GByteArray *ssid) +{ + return FALSE; +} + +/******************************************************************/ + +static GArray * +ip4_address_get_all (NMPlatform *platform, int ifindex) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + GArray *addresses; + NMPlatformIP4Address *address; + int count = 0, i; + + /* Count addresses */ + for (i = 0; i < priv->ip4_addresses->len; i++) { + address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); + if (address && address->ifindex == ifindex) + count++; + } + + addresses = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP4Address), count); + + /* Fill addresses */ + for (i = 0; i < priv->ip4_addresses->len; i++) { + address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); + if (address && address->ifindex == ifindex) + g_array_append_val (addresses, *address); + } + + return addresses; +} + +static GArray * +ip6_address_get_all (NMPlatform *platform, int ifindex) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + GArray *addresses; + NMPlatformIP6Address *address; + int count = 0, i; + + /* Count addresses */ + for (i = 0; i < priv->ip6_addresses->len; i++) { + address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i); + if (address && address->ifindex == ifindex) + count++; + } + + addresses = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP6Address), count); + + /* Fill addresses */ + count = 0; + for (i = 0; i < priv->ip6_addresses->len; i++) { + address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i); + if (address && address->ifindex == ifindex) + g_array_append_val (addresses, *address); + } + + return addresses; +} + +static gboolean +ip4_address_add (NMPlatform *platform, int ifindex, + in_addr_t addr, in_addr_t peer_addr, + int plen, guint32 lifetime, guint32 preferred, + const char *label) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + NMPlatformIP4Address address; + int i; + + memset (&address, 0, sizeof (address)); + address.source = NM_PLATFORM_SOURCE_KERNEL; + address.ifindex = ifindex; + address.address = addr; + address.peer_address = peer_addr; + address.plen = plen; + address.timestamp = nm_utils_get_monotonic_timestamp_s (); + address.lifetime = lifetime; + address.preferred = preferred; + if (label) + g_strlcpy (address.label, label, sizeof (address.label)); + + for (i = 0; i < priv->ip4_addresses->len; i++) { + NMPlatformIP4Address *item = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); + + if (item->ifindex != address.ifindex) + continue; + if (item->address != address.address) + continue; + if (item->plen != address.plen) + continue; + + memcpy (item, &address, sizeof (address)); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); + return TRUE; + } + + g_array_append_val (priv->ip4_addresses, address); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, ifindex, &address, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); + + return TRUE; +} + +static gboolean +ip6_address_add (NMPlatform *platform, int ifindex, + struct in6_addr addr, struct in6_addr peer_addr, + int plen, guint32 lifetime, guint32 preferred, guint flags) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + NMPlatformIP6Address address; + int i; + + memset (&address, 0, sizeof (address)); + address.source = NM_PLATFORM_SOURCE_KERNEL; + address.ifindex = ifindex; + address.address = addr; + address.peer_address = peer_addr; + address.plen = plen; + address.timestamp = nm_utils_get_monotonic_timestamp_s (); + address.lifetime = lifetime; + address.preferred = preferred; + address.flags = flags; + + for (i = 0; i < priv->ip6_addresses->len; i++) { + NMPlatformIP6Address *item = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i); + + if (item->ifindex != address.ifindex) + continue; + if (!IN6_ARE_ADDR_EQUAL (&item->address, &address.address)) + continue; + if (item->plen != address.plen) + continue; + + memcpy (item, &address, sizeof (address)); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); + return TRUE; + } + + g_array_append_val (priv->ip6_addresses, address); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, ifindex, &address, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); + + return TRUE; +} + +static gboolean +ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + int i; + + for (i = 0; i < priv->ip4_addresses->len; i++) { + NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); + + if (address->ifindex == ifindex && address->plen == plen && address->address == addr) { + NMPlatformIP4Address deleted_address; + + memcpy (&deleted_address, address, sizeof (deleted_address)); + memset (address, 0, sizeof (*address)); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, ifindex, &deleted_address, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_INTERNAL); + return TRUE; + } + } + + return TRUE; +} + +static gboolean +ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + int i; + + for (i = 0; i < priv->ip6_addresses->len; i++) { + NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i); + + if (address->ifindex == ifindex && address->plen == plen + && IN6_ARE_ADDR_EQUAL (&address->address, &addr)) { + NMPlatformIP6Address deleted_address; + + memcpy (&deleted_address, address, sizeof (deleted_address)); + memset (address, 0, sizeof (*address)); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, ifindex, &deleted_address, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_INTERNAL); + return TRUE; + } + } + + return TRUE; +} + +static gboolean +ip4_address_exists (NMPlatform *platform, int ifindex, in_addr_t addr, int plen) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + int i; + + for (i = 0; i < priv->ip4_addresses->len; i++) { + NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); + + if (address->ifindex == ifindex && address->plen == plen && address->address == addr) + return TRUE; + } + + return FALSE; +} + +static gboolean +ip6_address_exists (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + int i; + + for (i = 0; i < priv->ip6_addresses->len; i++) { + NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i); + + if (address->ifindex == ifindex && address->plen == plen && + IN6_ARE_ADDR_EQUAL (&address->address, &addr)) + return TRUE; + } + + return FALSE; +} + +/******************************************************************/ + +static GArray * +ip4_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + GArray *routes; + NMPlatformIP4Route *route; + int count = 0, i; + + /* Count routes */ + for (i = 0; i < priv->ip4_routes->len; i++) { + route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); + if (route && route->ifindex == ifindex) + count++; + } + + routes = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP4Route), count); + + /* Fill routes */ + for (i = 0; i < priv->ip4_routes->len; i++) { + route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); + if (route && route->ifindex == ifindex) { + if (route->plen != 0 || include_default) + g_array_append_val (routes, *route); + } + } + + return routes; +} + +static GArray * +ip6_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + GArray *routes; + NMPlatformIP6Route *route; + int count = 0, i; + + /* Count routes */ + for (i = 0; i < priv->ip6_routes->len; i++) { + route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); + if (route && route->ifindex == ifindex) + count++; + } + + routes = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP6Route), count); + + /* Fill routes */ + for (i = 0; i < priv->ip6_routes->len; i++) { + route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); + if (route && route->ifindex == ifindex) { + if (route->plen != 0 || include_default) + g_array_append_val (routes, *route); + } + } + + return routes; +} + +static gboolean +ip4_route_add (NMPlatform *platform, int ifindex, NMPlatformSource source, + in_addr_t network, int plen, in_addr_t gateway, + int metric, int mss) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + NMPlatformIP4Route route; + guint i; + + memset (&route, 0, sizeof (route)); + route.source = NM_PLATFORM_SOURCE_KERNEL; + route.ifindex = ifindex; + route.source = source; + route.network = network; + route.plen = plen; + route.gateway = gateway; + route.metric = metric; + route.mss = mss; + + for (i = 0; i < priv->ip4_routes->len; i++) { + NMPlatformIP4Route *item = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); + + if (item->ifindex != route.ifindex) + continue; + if (item->network != route.network) + continue; + if (item->plen != route.plen) + continue; + + memcpy (item, &route, sizeof (route)); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, ifindex, &route, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); + return TRUE; + } + + g_array_append_val (priv->ip4_routes, route); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, ifindex, &route, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); + + return TRUE; +} + +static gboolean +ip6_route_add (NMPlatform *platform, int ifindex, NMPlatformSource source, + struct in6_addr network, int plen, struct in6_addr gateway, + int metric, int mss) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + NMPlatformIP6Route route; + guint i; + + memset (&route, 0, sizeof (route)); + route.source = NM_PLATFORM_SOURCE_KERNEL; + route.ifindex = ifindex; + route.source = source; + route.network = network; + route.plen = plen; + route.gateway = gateway; + route.metric = metric; + route.mss = mss; + + for (i = 0; i < priv->ip6_routes->len; i++) { + NMPlatformIP6Route *item = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); + + if (item->ifindex != route.ifindex) + continue; + if (!IN6_ARE_ADDR_EQUAL (&item->network, &route.network)) + continue; + if (item->plen != route.plen) + continue; + + memcpy (item, &route, sizeof (route)); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, ifindex, &route, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); + return TRUE; + } + + g_array_append_val (priv->ip6_routes, route); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, ifindex, &route, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); + + return TRUE; +} + +static NMPlatformIP4Route * +ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, int plen, int metric) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + int i; + + for (i = 0; i < priv->ip4_routes->len; i++) { + NMPlatformIP4Route *route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); + + if (route->ifindex == ifindex + && route->network == network + && route->plen == plen + && route->metric == metric) + return route; + } + + return NULL; +} + +static NMPlatformIP6Route * +ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, int metric) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + int i; + + for (i = 0; i < priv->ip6_routes->len; i++) { + NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); + + if (route->ifindex == ifindex + && IN6_ARE_ADDR_EQUAL (&route->network, &network) + && route->plen == plen + && route->metric == metric) + return route; + } + + return NULL; +} + +static gboolean +ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen, int metric) +{ + NMPlatformIP4Route *route = ip4_route_get (platform, ifindex, network, plen, metric); + NMPlatformIP4Route deleted_route; + + if (route) { + memcpy (&deleted_route, route, sizeof (deleted_route)); + memset (route, 0, sizeof (*route)); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, ifindex, &deleted_route, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_INTERNAL); + } + + return TRUE; +} + +static gboolean +ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, int metric) +{ + NMPlatformIP6Route *route = ip6_route_get (platform, ifindex, network, plen, metric); + NMPlatformIP6Route deleted_route; + + if (route) { + memcpy (&deleted_route, route, sizeof (deleted_route)); + memset (route, 0, sizeof (*route)); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, ifindex, &deleted_route, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_INTERNAL); + } + + return TRUE; +} + +static gboolean +ip4_route_exists (NMPlatform *platform, int ifindex, in_addr_t network, int plen, int metric) +{ + return !!ip4_route_get (platform, ifindex, network, plen, metric); +} + +static gboolean +ip6_route_exists (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, int metric) +{ + return !!ip6_route_get (platform, ifindex, network, plen, metric); +} + +/******************************************************************/ + +static void +nm_fake_platform_init (NMFakePlatform *fake_platform) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (fake_platform); + + priv->options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + priv->links = g_array_new (TRUE, TRUE, sizeof (NMFakePlatformLink)); + priv->ip4_addresses = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Address)); + priv->ip6_addresses = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Address)); + priv->ip4_routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Route)); + priv->ip6_routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Route)); +} + +static gboolean +setup (NMPlatform *platform) +{ + /* skip zero element */ + link_add (platform, NULL, NM_LINK_TYPE_NONE, NULL, 0); + + /* add loopback interface */ + link_add (platform, "lo", NM_LINK_TYPE_LOOPBACK, NULL, 0); + + /* add some ethernets */ + link_add (platform, "eth0", NM_LINK_TYPE_ETHERNET, NULL, 0); + link_add (platform, "eth1", NM_LINK_TYPE_ETHERNET, NULL, 0); + link_add (platform, "eth2", NM_LINK_TYPE_ETHERNET, NULL, 0); + + return TRUE; +} + +static void +nm_fake_platform_finalize (GObject *object) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (object); + int i; + + g_hash_table_unref (priv->options); + for (i = 0; i < priv->links->len; i++) { + NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i); + + g_bytes_unref (device->address); + g_free (device->udi); + } + g_array_unref (priv->links); + g_array_unref (priv->ip4_addresses); + g_array_unref (priv->ip6_addresses); + g_array_unref (priv->ip4_routes); + g_array_unref (priv->ip6_routes); + + G_OBJECT_CLASS (nm_fake_platform_parent_class)->finalize (object); +} + +static void +nm_fake_platform_class_init (NMFakePlatformClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMPlatformClass *platform_class = NM_PLATFORM_CLASS (klass); + + g_type_class_add_private (klass, sizeof (NMFakePlatformPrivate)); + + /* virtual methods */ + object_class->finalize = nm_fake_platform_finalize; + + platform_class->setup = setup; + + platform_class->sysctl_set = sysctl_set; + platform_class->sysctl_get = sysctl_get; + + platform_class->link_get = _nm_platform_link_get; + platform_class->link_get_all = link_get_all; + platform_class->link_add = link_add; + platform_class->link_delete = link_delete; + platform_class->link_get_ifindex = link_get_ifindex; + platform_class->link_get_name = link_get_name; + platform_class->link_get_type = link_get_type; + platform_class->link_get_type_name = link_get_type_name; + + platform_class->link_set_up = link_set_up; + platform_class->link_set_down = link_set_down; + platform_class->link_set_arp = link_set_arp; + platform_class->link_set_noarp = link_set_noarp; + platform_class->link_is_up = link_is_up; + platform_class->link_is_connected = link_is_connected; + platform_class->link_uses_arp = link_uses_arp; + + platform_class->link_set_address = link_set_address; + platform_class->link_get_address = link_get_address; + platform_class->link_get_mtu = link_get_mtu; + platform_class->link_set_mtu = link_set_mtu; + + platform_class->link_get_physical_port_id = link_get_physical_port_id; + platform_class->link_get_wake_on_lan = link_get_wake_on_lan; + + platform_class->link_supports_carrier_detect = link_supports_carrier_detect; + platform_class->link_supports_vlans = link_supports_vlans; + + platform_class->link_enslave = link_enslave; + platform_class->link_release = link_release; + platform_class->link_get_master = link_get_master; + platform_class->master_set_option = master_set_option; + platform_class->master_get_option = master_get_option; + platform_class->slave_set_option = slave_set_option; + platform_class->slave_get_option = slave_get_option; + + platform_class->vlan_add = vlan_add; + platform_class->vlan_get_info = vlan_get_info; + platform_class->vlan_set_ingress_map = vlan_set_ingress_map; + platform_class->vlan_set_egress_map = vlan_set_egress_map; + + platform_class->infiniband_partition_add = infiniband_partition_add; + + platform_class->veth_get_properties = veth_get_properties; + platform_class->tun_get_properties = tun_get_properties; + platform_class->macvlan_get_properties = macvlan_get_properties; + platform_class->vxlan_get_properties = vxlan_get_properties; + platform_class->gre_get_properties = gre_get_properties; + + platform_class->wifi_get_capabilities = wifi_get_capabilities; + platform_class->wifi_get_bssid = wifi_get_bssid; + platform_class->wifi_get_ssid = wifi_get_ssid; + platform_class->wifi_get_frequency = wifi_get_frequency; + platform_class->wifi_get_quality = wifi_get_quality; + platform_class->wifi_get_rate = wifi_get_rate; + platform_class->wifi_get_mode = wifi_get_mode; + platform_class->wifi_set_mode = wifi_set_mode; + platform_class->wifi_find_frequency = wifi_find_frequency; + platform_class->wifi_indicate_addressing_running = wifi_indicate_addressing_running; + + platform_class->mesh_get_channel = mesh_get_channel; + platform_class->mesh_set_channel = mesh_set_channel; + platform_class->mesh_set_ssid = mesh_set_ssid; + + platform_class->ip4_address_get_all = ip4_address_get_all; + platform_class->ip6_address_get_all = ip6_address_get_all; + platform_class->ip4_address_add = ip4_address_add; + platform_class->ip6_address_add = ip6_address_add; + platform_class->ip4_address_delete = ip4_address_delete; + platform_class->ip6_address_delete = ip6_address_delete; + platform_class->ip4_address_exists = ip4_address_exists; + platform_class->ip6_address_exists = ip6_address_exists; + + platform_class->ip4_route_get_all = ip4_route_get_all; + platform_class->ip6_route_get_all = ip6_route_get_all; + platform_class->ip4_route_add = ip4_route_add; + platform_class->ip6_route_add = ip6_route_add; + platform_class->ip4_route_delete = ip4_route_delete; + platform_class->ip6_route_delete = ip6_route_delete; + platform_class->ip4_route_exists = ip4_route_exists; + platform_class->ip6_route_exists = ip6_route_exists; +} diff --git a/src/platform/nm-fake-platform.h b/src/platform/nm-fake-platform.h new file mode 100644 index 00000000..c9fa42eb --- /dev/null +++ b/src/platform/nm-fake-platform.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-fake-platform.h - Fake platform interaction code for testing NetworkManager + * + * 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, 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) 2012 Red Hat, Inc. + */ + +#ifndef NM_FAKE_PLATFORM_H +#define NM_FAKE_PLATFORM_H + +#include "nm-platform.h" + +#define NM_TYPE_FAKE_PLATFORM (nm_fake_platform_get_type ()) +#define NM_FAKE_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_FAKE_PLATFORM, NMFakePlatform)) +#define NM_FAKE_PLATFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_FAKE_PLATFORM, NMFakePlatformClass)) +#define NM_IS_FAKE_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_FAKE_PLATFORM)) +#define NM_IS_FAKE_PLATFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_FAKE_PLATFORM)) +#define NM_FAKE_PLATFORM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_FAKE_PLATFORM, NMFakePlatformClass)) + +/******************************************************************/ + +typedef struct { + NMPlatform parent; +} NMFakePlatform; + +typedef struct { + NMPlatformClass parent; +} NMFakePlatformClass; + +/******************************************************************/ + +GType nm_fake_platform_get_type (void); + +void nm_fake_platform_setup (void); + +#endif /* NM_FAKE_PLATFORM_H */ diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c new file mode 100644 index 00000000..f73ff320 --- /dev/null +++ b/src/platform/nm-linux-platform.c @@ -0,0 +1,4180 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-linux-platform.c - Linux kernel & udev network configuration layer + * + * 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, 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) 2012-2013 Red Hat, Inc. + */ +#include <config.h> + +#include <errno.h> +#include <unistd.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <dlfcn.h> +#include <netinet/icmp6.h> +#include <netinet/in.h> +#include <linux/ip.h> +#include <linux/if_arp.h> +#include <linux/if_link.h> +#include <linux/if_tun.h> +#include <linux/if_tunnel.h> +#include <sys/ioctl.h> +#include <linux/sockios.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <netlink/netlink.h> +#include <netlink/object.h> +#include <netlink/cache.h> +#include <netlink/route/link.h> +#include <netlink/route/link/vlan.h> +#include <netlink/route/addr.h> +#include <netlink/route/route.h> +#include <gudev/gudev.h> + +#include "NetworkManagerUtils.h" +#include "nm-linux-platform.h" +#include "NetworkManagerUtils.h" +#include "nm-utils.h" +#include "nm-logging.h" +#include "wifi/wifi-utils.h" +#include "wifi/wifi-utils-wext.h" + +/* This is only included for the translation of VLAN flags */ +#include "nm-setting-vlan.h" + +#define debug(...) nm_log_dbg (LOGD_PLATFORM, __VA_ARGS__) +#define warning(...) nm_log_warn (LOGD_PLATFORM, __VA_ARGS__) +#define error(...) nm_log_err (LOGD_PLATFORM, __VA_ARGS__) + + +struct libnl_vtable +{ + void *handle; + + int (*f_nl_has_capability) (int capability); +}; + + +typedef struct { + struct nl_sock *nlh; + struct nl_sock *nlh_event; + struct nl_cache *link_cache; + struct nl_cache *address_cache; + struct nl_cache *route_cache; + GIOChannel *event_channel; + guint event_id; + + GUdevClient *udev_client; + GHashTable *udev_devices; + + GHashTable *wifi_data; + + int support_kernel_extended_ifa_flags; +} NMLinuxPlatformPrivate; + +#define NM_LINUX_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformPrivate)) + +G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM) + +static const char *to_string_object (NMPlatform *platform, struct nl_object *obj); + +void +nm_linux_platform_setup (void) +{ + nm_platform_setup (NM_TYPE_LINUX_PLATFORM); +} + +/******************************************************************/ + +static int +_nl_f_nl_has_capability (int capability) +{ + return FALSE; +} + +static struct libnl_vtable * +_nl_get_vtable () +{ + static struct libnl_vtable vtable; + + if (G_UNLIKELY (!vtable.f_nl_has_capability)) { + void *handle; + + handle = dlopen ("libnl-3.so", RTLD_LAZY | RTLD_NOLOAD); + if (handle) { + vtable.handle = handle; + vtable.f_nl_has_capability = dlsym (handle, "nl_has_capability"); + } + + if (!vtable.f_nl_has_capability) + vtable.f_nl_has_capability = &_nl_f_nl_has_capability; + + g_return_val_if_fail (vtable.handle, &vtable); + } + + return &vtable; +} + +static gboolean +_nl_has_capability (int capability) +{ + return (_nl_get_vtable ()->f_nl_has_capability) (capability); +} + +/******************************************************************/ + +static guint32 +_get_expiry (guint32 now_s, guint32 lifetime_s) +{ + gint64 t = ((gint64) now_s) + ((gint64) lifetime_s); + + return MIN (t, NM_PLATFORM_LIFETIME_PERMANENT - 1); +} + +/* The rtnl_addr object contains relative lifetimes @valid and @preferred + * that count in seconds, starting from the moment when the kernel constructed + * the netlink message. + * + * There is also a field rtnl_addr_last_update_time(), which is the absolute + * time in 1/100th of a second of clock_gettime (CLOCK_MONOTONIC) when the address + * was modified (wrapping every 497 days). + * Immediately at the time when the address was last modified, #NOW and @last_update_time + * are the same, so (only) in that case @valid and @preferred are anchored at @last_update_time. + * However, this is not true in general. As time goes by, whenever kernel sends a new address + * via netlink, the lifetimes keep counting down. + * + * As we cache the rtnl_addr object we must know the absolute expiries. + * As a hack, modify the relative timestamps valid and preferred into absolute + * timestamps of scale nm_utils_get_monotonic_timestamp_s(). + **/ +static void +_rtnl_addr_hack_lifetimes_rel_to_abs (struct rtnl_addr *rtnladdr) +{ + guint32 a_valid = rtnl_addr_get_valid_lifetime (rtnladdr); + guint32 a_preferred = rtnl_addr_get_preferred_lifetime (rtnladdr); + guint32 now; + + if (a_valid == NM_PLATFORM_LIFETIME_PERMANENT && + a_preferred == NM_PLATFORM_LIFETIME_PERMANENT) + return; + + now = (guint32) nm_utils_get_monotonic_timestamp_s (); + + if (a_preferred > a_valid) + a_preferred = a_valid; + + if (a_valid != NM_PLATFORM_LIFETIME_PERMANENT) + rtnl_addr_set_valid_lifetime (rtnladdr, _get_expiry (now, a_valid)); + rtnl_addr_set_preferred_lifetime (rtnladdr, _get_expiry (now, a_preferred)); +} + +/******************************************************************/ + +/* libnl library workarounds and additions */ + +/* Automatic deallocation of local variables */ +#define auto_nl_cache __attribute__((cleanup(put_nl_cache))) +static void +put_nl_cache (void *ptr) +{ + struct nl_cache **cache = ptr; + + if (cache && *cache) { + nl_cache_free (*cache); + *cache = NULL; + } +} + +#define auto_nl_object __attribute__((cleanup(put_nl_object))) +static void +put_nl_object (void *ptr) +{ + struct nl_object **object = ptr; + + if (object && *object) { + nl_object_put (*object); + *object = NULL; + } +} + +#define auto_nl_addr __attribute__((cleanup(put_nl_addr))) +static void +put_nl_addr (void *ptr) +{ + struct nl_addr **object = ptr; + + if (object && *object) { + nl_addr_put (*object); + *object = NULL; + } +} + +/*******************************************************************/ + +/* wrap the libnl alloc functions and abort on out-of-memory*/ + +static struct nl_addr * +_nm_nl_addr_build (int family, const void *buf, size_t size) +{ + struct nl_addr *addr; + + addr = nl_addr_build (family, (void *) buf, size); + if (!addr) + g_error ("nl_addr_build() failed with out of memory"); + + return addr; +} + +static struct rtnl_link * +_nm_rtnl_link_alloc (int ifindex, const char*name) +{ + struct rtnl_link *rtnllink; + + rtnllink = rtnl_link_alloc (); + if (!rtnllink) + g_error ("rtnl_link_alloc() failed with out of memory"); + + if (ifindex > 0) + rtnl_link_set_ifindex (rtnllink, ifindex); + if (name) + rtnl_link_set_name (rtnllink, name); + return rtnllink; +} + +static struct rtnl_addr * +_nm_rtnl_addr_alloc (int ifindex) +{ + struct rtnl_addr *rtnladdr; + + rtnladdr = rtnl_addr_alloc (); + if (!rtnladdr) + g_error ("rtnl_addr_alloc() failed with out of memory"); + if (ifindex > 0) + rtnl_addr_set_ifindex (rtnladdr, ifindex); + return rtnladdr; +} + +static struct rtnl_route * +_nm_rtnl_route_alloc () +{ + struct rtnl_route *rtnlroute = rtnl_route_alloc (); + + if (!rtnlroute) + g_error ("rtnl_route_alloc() failed with out of memory"); + return rtnlroute; +} + +static struct rtnl_nexthop * +_nm_rtnl_route_nh_alloc () +{ + struct rtnl_nexthop *nexthop; + + nexthop = rtnl_route_nh_alloc (); + if (!nexthop) + g_error ("rtnl_route_nh_alloc () failed with out of memory"); + return nexthop; +} + +/*******************************************************************/ + +/* rtnl_addr_set_prefixlen fails to update the nl_addr prefixlen */ +static void +nm_rtnl_addr_set_prefixlen (struct rtnl_addr *rtnladdr, int plen) +{ + struct nl_addr *nladdr; + + rtnl_addr_set_prefixlen (rtnladdr, plen); + + nladdr = rtnl_addr_get_local (rtnladdr); + if (nladdr) + nl_addr_set_prefixlen (nladdr, plen); +} +#define rtnl_addr_set_prefixlen nm_rtnl_addr_set_prefixlen + +typedef enum { + OBJECT_TYPE_UNKNOWN, + OBJECT_TYPE_LINK, + OBJECT_TYPE_IP4_ADDRESS, + OBJECT_TYPE_IP6_ADDRESS, + OBJECT_TYPE_IP4_ROUTE, + OBJECT_TYPE_IP6_ROUTE, + __OBJECT_TYPE_LAST, +} ObjectType; + +static ObjectType +object_type_from_nl_object (const struct nl_object *object) +{ + const char *type_str; + + if (!object || !(type_str = nl_object_get_type (object))) + return OBJECT_TYPE_UNKNOWN; + + if (!strcmp (type_str, "route/link")) + return OBJECT_TYPE_LINK; + else if (!strcmp (type_str, "route/addr")) { + switch (rtnl_addr_get_family ((struct rtnl_addr *) object)) { + case AF_INET: + return OBJECT_TYPE_IP4_ADDRESS; + case AF_INET6: + return OBJECT_TYPE_IP6_ADDRESS; + default: + return OBJECT_TYPE_UNKNOWN; + } + } else if (!strcmp (type_str, "route/route")) { + switch (rtnl_route_get_family ((struct rtnl_route *) object)) { + case AF_INET: + return OBJECT_TYPE_IP4_ROUTE; + case AF_INET6: + return OBJECT_TYPE_IP6_ROUTE; + default: + return OBJECT_TYPE_UNKNOWN; + } + } else + return OBJECT_TYPE_UNKNOWN; +} + +static void +_nl_link_family_unset (struct nl_object *obj, int *family) +{ + if (!obj || object_type_from_nl_object (obj) != OBJECT_TYPE_LINK) + *family = AF_UNSPEC; + else { + *family = rtnl_link_get_family ((struct rtnl_link *) obj); + + /* Always explicitly set the family to AF_UNSPEC, even if rtnl_link_get_family() might + * already return %AF_UNSPEC. The reason is, that %AF_UNSPEC is the default family + * and libnl nl_object_identical() function will only succeed, if the family is + * explicitly set (which we cannot be sure, unless setting it). */ + rtnl_link_set_family ((struct rtnl_link *) obj, AF_UNSPEC); + } +} + +/* In our link cache, we coerce the family of all link objects to AF_UNSPEC. + * Thus, before searching for an object, we fixup @needle to have the right + * id (by resetting the family). */ +static struct nl_object * +nm_nl_cache_search (struct nl_cache *cache, struct nl_object *needle) +{ + int family; + struct nl_object *obj; + + _nl_link_family_unset (needle, &family); + obj = nl_cache_search (cache, needle); + if (family != AF_UNSPEC) { + /* restore the family of the @needle instance. If the family was + * unset before, we cannot make it unset again. Thus, in that case + * we cannot undo _nl_link_family_unset() entirely. */ + rtnl_link_set_family ((struct rtnl_link *) needle, family); + } + + return obj; +} + +/* Ask the kernel for an object identical (as in nl_cache_identical) to the + * needle argument. This is a kernel counterpart for nl_cache_search. + * + * The returned object must be freed by the caller with nl_object_put(). + */ +static struct nl_object * +get_kernel_object (struct nl_sock *sock, struct nl_object *needle) +{ + struct nl_object *object = NULL; + ObjectType type = object_type_from_nl_object (needle); + + switch (type) { + case OBJECT_TYPE_LINK: + { + int ifindex = rtnl_link_get_ifindex ((struct rtnl_link *) needle); + const char *name = rtnl_link_get_name ((struct rtnl_link *) needle); + int nle; + + nle = rtnl_link_get_kernel (sock, ifindex, name, (struct rtnl_link **) &object); + switch (nle) { + case -NLE_SUCCESS: + if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) { + name = rtnl_link_get_name ((struct rtnl_link *) object); + debug ("get_kernel_object for link: %s (%d, family %d)", + name ? name : "(unknown)", + rtnl_link_get_ifindex ((struct rtnl_link *) object), + rtnl_link_get_family ((struct rtnl_link *) object)); + } + + _nl_link_family_unset (object, &nle); + return object; + case -NLE_NODEV: + debug ("get_kernel_object for link %s (%d) had no result", + name ? name : "(unknown)", ifindex); + return NULL; + default: + error ("get_kernel_object for link %s (%d) failed: %s (%d)", + name ? name : "(unknown)", ifindex, nl_geterror (nle), nle); + return NULL; + } + } + case OBJECT_TYPE_IP4_ADDRESS: + case OBJECT_TYPE_IP6_ADDRESS: + case OBJECT_TYPE_IP4_ROUTE: + case OBJECT_TYPE_IP6_ROUTE: + /* Fallback to a one-time cache allocation. */ + { + struct nl_cache *cache; + int nle; + + /* FIXME: every time we refresh *one* object, we request an + * entire dump. E.g. check_cache_items() gets O(n2) complexitly. */ + + nle = nl_cache_alloc_and_fill ( + nl_cache_ops_lookup (nl_object_get_type (needle)), + sock, &cache); + if (nle) { + error ("get_kernel_object for type %d failed: %s (%d)", + type, nl_geterror (nle), nle); + return NULL; + } + + object = nl_cache_search (cache, needle); + + nl_cache_free (cache); + + if (object && (type == OBJECT_TYPE_IP4_ADDRESS || type == OBJECT_TYPE_IP6_ADDRESS)) + _rtnl_addr_hack_lifetimes_rel_to_abs ((struct rtnl_addr *) object); + + if (object) + debug ("get_kernel_object for type %d returned %p", type, object); + else + debug ("get_kernel_object for type %d had no result", type); + return object; + } + default: + g_return_val_if_reached (NULL); + return NULL; + } +} + +/* libnl 3.2 doesn't seem to provide such a generic way to add libnl-route objects. */ +static int +add_kernel_object (struct nl_sock *sock, struct nl_object *object) +{ + switch (object_type_from_nl_object (object)) { + case OBJECT_TYPE_LINK: + return rtnl_link_add (sock, (struct rtnl_link *) object, NLM_F_CREATE); + case OBJECT_TYPE_IP4_ADDRESS: + case OBJECT_TYPE_IP6_ADDRESS: + return rtnl_addr_add (sock, (struct rtnl_addr *) object, NLM_F_CREATE | NLM_F_REPLACE); + case OBJECT_TYPE_IP4_ROUTE: + case OBJECT_TYPE_IP6_ROUTE: + return rtnl_route_add (sock, (struct rtnl_route *) object, NLM_F_CREATE | NLM_F_REPLACE); + default: + g_return_val_if_reached (-NLE_INVAL); + return -NLE_INVAL; + } +} + +/* nm_rtnl_link_parse_info_data(): Re-fetches a link from the kernel + * and parses its IFLA_INFO_DATA using a caller-provided parser. + * + * Code is stolen from rtnl_link_get_kernel(), nl_pickup(), and link_msg_parser(). + */ + +typedef int (*NMNLInfoDataParser) (struct nlattr *info_data, gpointer parser_data); + +typedef struct { + NMNLInfoDataParser parser; + gpointer parser_data; +} NMNLInfoDataClosure; + +static struct nla_policy info_data_link_policy[IFLA_MAX + 1] = { + [IFLA_LINKINFO] = { .type = NLA_NESTED }, +}; + +static struct nla_policy info_data_link_info_policy[IFLA_INFO_MAX + 1] = { + [IFLA_INFO_DATA] = { .type = NLA_NESTED }, +}; + +static int +info_data_parser (struct nl_msg *msg, void *arg) +{ + NMNLInfoDataClosure *closure = arg; + struct nlmsghdr *n = nlmsg_hdr (msg); + struct nlattr *tb[IFLA_MAX + 1]; + struct nlattr *li[IFLA_INFO_MAX + 1]; + int err; + + if (!nlmsg_valid_hdr (n, sizeof (struct ifinfomsg))) + return -NLE_MSG_TOOSHORT; + + err = nlmsg_parse (n, sizeof (struct ifinfomsg), tb, IFLA_MAX, info_data_link_policy); + if (err < 0) + return err; + + if (!tb[IFLA_LINKINFO]) + return -NLE_MISSING_ATTR; + + err = nla_parse_nested (li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], info_data_link_info_policy); + if (err < 0) + return err; + + if (!li[IFLA_INFO_DATA]) + return -NLE_MISSING_ATTR; + + return closure->parser (li[IFLA_INFO_DATA], closure->parser_data); +} + +static int +nm_rtnl_link_parse_info_data (struct nl_sock *sk, int ifindex, + NMNLInfoDataParser parser, gpointer parser_data) +{ + NMNLInfoDataClosure data = { .parser = parser, .parser_data = parser_data }; + struct nl_msg *msg = NULL; + struct nl_cb *cb; + int err; + + err = rtnl_link_build_get_request (ifindex, NULL, &msg); + if (err < 0) + return err; + + err = nl_send_auto (sk, msg); + nlmsg_free (msg); + if (err < 0) + return err; + + cb = nl_cb_clone (nl_socket_get_cb (sk)); + if (cb == NULL) + return -NLE_NOMEM; + nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, info_data_parser, &data); + + err = nl_recvmsgs (sk, cb); + nl_cb_put (cb); + if (err < 0) + return err; + + nl_wait_for_ack (sk); + return 0; +} + +/******************************************************************/ + +static gboolean +ethtool_get (const char *name, gpointer edata) +{ + struct ifreq ifr; + int fd; + + memset (&ifr, 0, sizeof (ifr)); + strncpy (ifr.ifr_name, name, IFNAMSIZ); + ifr.ifr_data = edata; + + fd = socket (PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + error ("ethtool: Could not open socket."); + return FALSE; + } + + if (ioctl (fd, SIOCETHTOOL, &ifr) < 0) { + debug ("ethtool: Request failed: %s", strerror (errno)); + close (fd); + return FALSE; + } + + close (fd); + return TRUE; +} + +static int +ethtool_get_stringset_index (const char *ifname, int stringset_id, const char *string) +{ + auto_g_free struct ethtool_sset_info *info = NULL; + auto_g_free struct ethtool_gstrings *strings = NULL; + guint32 len, i; + + info = g_malloc0 (sizeof (*info) + sizeof (guint32)); + info->cmd = ETHTOOL_GSSET_INFO; + info->reserved = 0; + info->sset_mask = 1ULL << stringset_id; + + if (!ethtool_get (ifname, info)) + return -1; + if (!info->sset_mask) + return -1; + + len = info->data[0]; + + strings = g_malloc0 (sizeof (*strings) + len * ETH_GSTRING_LEN); + strings->cmd = ETHTOOL_GSTRINGS; + strings->string_set = stringset_id; + strings->len = len; + if (!ethtool_get (ifname, strings)) + return -1; + + for (i = 0; i < len; i++) { + if (!strcmp ((char *) &strings->data[i * ETH_GSTRING_LEN], string)) + return i; + } + + return -1; +} + +/******************************************************************/ + +static void +_check_support_kernel_extended_ifa_flags_init (NMLinuxPlatformPrivate *priv, struct nl_msg *msg) +{ + struct nlmsghdr *msg_hdr = nlmsg_hdr (msg); + + g_return_if_fail (priv->support_kernel_extended_ifa_flags == 0); + g_return_if_fail (msg_hdr->nlmsg_type == RTM_NEWADDR); + + /* the extended address flags are only set for AF_INET6 */ + if (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family != AF_INET6) + return; + + /* see if the nl_msg contains the IFA_FLAGS attribute. If it does, + * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR + * and IFA_F_NOPREFIXROUTE (they were added together). + **/ + priv->support_kernel_extended_ifa_flags = + nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), 8 /* IFA_FLAGS */) + ? 1 : -1; +} + +static gboolean +check_support_kernel_extended_ifa_flags (NMPlatform *platform) +{ + NMLinuxPlatformPrivate *priv; + + g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE); + + priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + + if (priv->support_kernel_extended_ifa_flags == 0) { + nm_log_warn (LOGD_PLATFORM, "Unable to detect kernel support for extended IFA_FLAGS. Assume no kernel support."); + priv->support_kernel_extended_ifa_flags = -1; + } + + return priv->support_kernel_extended_ifa_flags > 0; +} + + +/* Object type specific utilities */ + +static const char * +type_to_string (NMLinkType type) +{ + /* Note that this only has to support virtual types */ + switch (type) { + case NM_LINK_TYPE_DUMMY: + return "dummy"; + case NM_LINK_TYPE_GRE: + return "gre"; + case NM_LINK_TYPE_GRETAP: + return "gretap"; + case NM_LINK_TYPE_IFB: + return "ifb"; + case NM_LINK_TYPE_MACVLAN: + return "macvlan"; + case NM_LINK_TYPE_MACVTAP: + return "macvtap"; + case NM_LINK_TYPE_TAP: + return "tap"; + case NM_LINK_TYPE_TUN: + return "tun"; + case NM_LINK_TYPE_VETH: + return "veth"; + case NM_LINK_TYPE_VLAN: + return "vlan"; + case NM_LINK_TYPE_VXLAN: + return "vxlan"; + case NM_LINK_TYPE_BRIDGE: + return "bridge"; + case NM_LINK_TYPE_BOND: + return "bond"; + case NM_LINK_TYPE_TEAM: + return "team"; + default: + g_warning ("Wrong type: %d", type); + return NULL; + } +} + +#define return_type(t, name) \ + G_STMT_START { \ + if (out_name) \ + *out_name = name; \ + return t; \ + } G_STMT_END + +static NMLinkType +link_type_from_udev (NMPlatform *platform, int ifindex, const char *ifname, int arptype, const char **out_name) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + GUdevDevice *udev_device; + const char *prop, *sysfs_path; + + g_assert (ifname); + + udev_device = g_hash_table_lookup (priv->udev_devices, GINT_TO_POINTER (ifindex)); + if (!udev_device) + return_type (NM_LINK_TYPE_UNKNOWN, "unknown"); + + if ( g_udev_device_get_property (udev_device, "ID_NM_OLPC_MESH") + || g_udev_device_get_sysfs_attr (udev_device, "anycast_mask")) + return_type (NM_LINK_TYPE_OLPC_MESH, "olpc-mesh"); + + prop = g_udev_device_get_property (udev_device, "DEVTYPE"); + sysfs_path = g_udev_device_get_sysfs_path (udev_device); + if (g_strcmp0 (prop, "wlan") == 0 || wifi_utils_is_wifi (ifname, sysfs_path)) + return_type (NM_LINK_TYPE_WIFI, "wifi"); + else if (g_strcmp0 (prop, "wwan") == 0) + return_type (NM_LINK_TYPE_WWAN_ETHERNET, "wwan"); + else if (g_strcmp0 (prop, "wimax") == 0) + return_type (NM_LINK_TYPE_WIMAX, "wimax"); + + if (arptype == ARPHRD_ETHER) + return_type (NM_LINK_TYPE_ETHERNET, "ethernet"); + + return_type (NM_LINK_TYPE_UNKNOWN, "unknown"); +} + +static gboolean +link_is_software (struct rtnl_link *rtnllink) +{ + const char *type; + + /* FIXME: replace somehow with NMLinkType or nm_platform_is_software(), but + * solve the infinite callstack problems that getting the type of a TUN/TAP + * device causes. + */ + + if ( rtnl_link_get_arptype (rtnllink) == ARPHRD_INFINIBAND + && strchr (rtnl_link_get_name (rtnllink), '.')) + return TRUE; + + type = rtnl_link_get_type (rtnllink); + if (type == NULL) + return FALSE; + + if (!strcmp (type, "dummy") || + !strcmp (type, "gre") || + !strcmp (type, "gretap") || + !strcmp (type, "macvlan") || + !strcmp (type, "macvtap") || + !strcmp (type, "tun") || + !strcmp (type, "veth") || + !strcmp (type, "vlan") || + !strcmp (type, "vxlan") || + !strcmp (type, "bridge") || + !strcmp (type, "bond") || + !strcmp (type, "team")) + return TRUE; + + return FALSE; +} + +static const char * +ethtool_get_driver (const char *ifname) +{ + struct ethtool_drvinfo drvinfo = { 0 }; + + g_return_val_if_fail (ifname != NULL, NULL); + + drvinfo.cmd = ETHTOOL_GDRVINFO; + if (!ethtool_get (ifname, &drvinfo)) + return NULL; + + if (!*drvinfo.driver) + return NULL; + + return g_intern_string (drvinfo.driver); +} + +static gboolean +link_is_announceable (NMPlatform *platform, struct rtnl_link *rtnllink) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + + /* Software devices are always visible outside the platform */ + if (link_is_software (rtnllink)) + return TRUE; + + /* Hardware devices must be found by udev so rules get run and tags set */ + if (g_hash_table_lookup (priv->udev_devices, + GINT_TO_POINTER (rtnl_link_get_ifindex (rtnllink)))) + return TRUE; + + return FALSE; +} + +static NMLinkType +link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink, const char **out_name) +{ + const char *type; + + if (!rtnllink) + return_type (NM_LINK_TYPE_NONE, NULL); + + type = rtnl_link_get_type (rtnllink); + + if (!type) { + int arptype = rtnl_link_get_arptype (rtnllink); + const char *driver; + const char *ifname; + + if (arptype == ARPHRD_LOOPBACK) + return_type (NM_LINK_TYPE_LOOPBACK, "loopback"); + else if (arptype == ARPHRD_INFINIBAND) + return_type (NM_LINK_TYPE_INFINIBAND, "infiniband"); + + ifname = rtnl_link_get_name (rtnllink); + if (!ifname) + return_type (NM_LINK_TYPE_UNKNOWN, type); + + if (arptype == 256) { + /* Some s390 CTC-type devices report 256 for the encapsulation type + * for some reason, but we need to call them Ethernet. FIXME: use + * something other than interface name to detect CTC here. + */ + if (g_str_has_prefix (ifname, "ctc")) + return_type (NM_LINK_TYPE_ETHERNET, "ethernet"); + } + + driver = ethtool_get_driver (ifname); + if (!g_strcmp0 (driver, "openvswitch")) + return_type (NM_LINK_TYPE_OPENVSWITCH, "openvswitch"); + + return link_type_from_udev (platform, + rtnl_link_get_ifindex (rtnllink), + ifname, + arptype, + out_name); + } else if (!strcmp (type, "dummy")) + return_type (NM_LINK_TYPE_DUMMY, "dummy"); + else if (!strcmp (type, "gre")) + return_type (NM_LINK_TYPE_GRE, "gre"); + else if (!strcmp (type, "gretap")) + return_type (NM_LINK_TYPE_GRETAP, "gretap"); + else if (!strcmp (type, "ifb")) + return_type (NM_LINK_TYPE_IFB, "ifb"); + else if (!strcmp (type, "macvlan")) + return_type (NM_LINK_TYPE_MACVLAN, "macvlan"); + else if (!strcmp (type, "macvtap")) + return_type (NM_LINK_TYPE_MACVTAP, "macvtap"); + else if (!strcmp (type, "tun")) { + NMPlatformTunProperties props; + guint flags; + + if (nm_platform_tun_get_properties (rtnl_link_get_ifindex (rtnllink), &props)) { + if (!g_strcmp0 (props.mode, "tap")) + return_type (NM_LINK_TYPE_TAP, "tap"); + if (!g_strcmp0 (props.mode, "tun")) + return_type (NM_LINK_TYPE_TUN, "tun"); + } + flags = rtnl_link_get_flags (rtnllink); + + nm_log_dbg (LOGD_PLATFORM, "Failed to read tun properties for interface %d (link flags: %X)", + rtnl_link_get_ifindex (rtnllink), flags); + + /* try guessing the type using the link flags instead... */ + if (flags & IFF_POINTOPOINT) + return_type (NM_LINK_TYPE_TUN, "tun"); + return_type (NM_LINK_TYPE_TAP, "tap"); + } else if (!strcmp (type, "veth")) + return_type (NM_LINK_TYPE_VETH, "veth"); + else if (!strcmp (type, "vlan")) + return_type (NM_LINK_TYPE_VLAN, "vlan"); + else if (!strcmp (type, "vxlan")) + return_type (NM_LINK_TYPE_VXLAN, "vxlan"); + else if (!strcmp (type, "bridge")) + return_type (NM_LINK_TYPE_BRIDGE, "bridge"); + else if (!strcmp (type, "bond")) + return_type (NM_LINK_TYPE_BOND, "bond"); + else if (!strcmp (type, "team")) + return_type (NM_LINK_TYPE_TEAM, "team"); + + return_type (NM_LINK_TYPE_UNKNOWN, type); +} + +static const char * +udev_get_driver (NMPlatform *platform, GUdevDevice *device, int ifindex) +{ + GUdevDevice *parent = NULL, *grandparent = NULL; + const char *driver, *subsys; + + driver = g_udev_device_get_driver (device); + if (driver) + return driver; + + /* Try the parent */ + parent = g_udev_device_get_parent (device); + if (parent) { + driver = g_udev_device_get_driver (parent); + if (!driver) { + /* Try the grandparent if it's an ibmebus device or if the + * subsys is NULL which usually indicates some sort of + * platform device like a 'gadget' net interface. + */ + subsys = g_udev_device_get_subsystem (parent); + if ( (g_strcmp0 (subsys, "ibmebus") == 0) + || (subsys == NULL)) { + grandparent = g_udev_device_get_parent (parent); + if (grandparent) { + driver = g_udev_device_get_driver (grandparent); + } + } + } + } + + /* Intern the string so we don't have to worry about memory + * management in NMPlatformLink. + */ + if (driver) + driver = g_intern_string (driver); + + g_clear_object (&parent); + g_clear_object (&grandparent); + + return driver; +} + +static gboolean +init_link (NMPlatform *platform, NMPlatformLink *info, struct rtnl_link *rtnllink) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + GUdevDevice *udev_device; + const char *name; + + g_return_val_if_fail (rtnllink, FALSE); + + name = rtnl_link_get_name (rtnllink); + memset (info, 0, sizeof (*info)); + + info->ifindex = rtnl_link_get_ifindex (rtnllink); + if (name) + g_strlcpy (info->name, name, sizeof (info->name)); + else + info->name[0] = '\0'; + info->type = link_extract_type (platform, rtnllink, &info->type_name); + info->up = !!(rtnl_link_get_flags (rtnllink) & IFF_UP); + info->connected = !!(rtnl_link_get_flags (rtnllink) & IFF_LOWER_UP); + info->arp = !(rtnl_link_get_flags (rtnllink) & IFF_NOARP); + info->master = rtnl_link_get_master (rtnllink); + info->parent = rtnl_link_get_link (rtnllink); + info->mtu = rtnl_link_get_mtu (rtnllink); + + udev_device = g_hash_table_lookup (priv->udev_devices, GINT_TO_POINTER (info->ifindex)); + if (udev_device) { + info->driver = udev_get_driver (platform, udev_device, info->ifindex); + if (!info->driver) + info->driver = rtnl_link_get_type (rtnllink); + if (!info->driver) + info->driver = ethtool_get_driver (info->name); + if (!info->driver) + info->driver = "unknown"; + info->udi = g_udev_device_get_sysfs_path (udev_device); + } + + return TRUE; +} + +/* Hack: Empty bridges and bonds have IFF_LOWER_UP flag and therefore they break + * the carrier detection. This hack makes nm-platform think they don't have the + * IFF_LOWER_UP flag. This seems to also apply to bonds (specifically) with all + * slaves down. + * + * Note: This is still a bit racy but when NetworkManager asks for enslaving a slave, + * nm-platform will do that synchronously and will immediately ask for both master + * and slave information after the enslaving request. After the synchronous call, the + * master carrier is already updated with the slave carrier in mind. + * + * https://bugzilla.redhat.com/show_bug.cgi?id=910348 + */ +static void +hack_empty_master_iff_lower_up (NMPlatform *platform, struct nl_object *object) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + struct rtnl_link *rtnllink; + int ifindex; + struct nl_object *slave; + const char *type; + + if (!object) + return; + if (strcmp (nl_object_get_type (object), "route/link")) + return; + + rtnllink = (struct rtnl_link *) object; + + ifindex = rtnl_link_get_ifindex (rtnllink); + + type = rtnl_link_get_type (rtnllink); + if (!type || (strcmp (type, "bridge") != 0 && strcmp (type, "bond") != 0)) + return; + + for (slave = nl_cache_get_first (priv->link_cache); slave; slave = nl_cache_get_next (slave)) { + struct rtnl_link *rtnlslave = (struct rtnl_link *) slave; + if (rtnl_link_get_master (rtnlslave) == ifindex + && rtnl_link_get_flags (rtnlslave) & IFF_LOWER_UP) + return; + } + + rtnl_link_unset_flags (rtnllink, IFF_LOWER_UP); +} + +static guint32 +_get_remaining_time (guint32 start_timestamp, guint32 end_timestamp) +{ + /* Return the remaining time between @start_timestamp until @end_timestamp. + * + * If @end_timestamp is NM_PLATFORM_LIFETIME_PERMANENT, it returns + * NM_PLATFORM_LIFETIME_PERMANENT. If @start_timestamp already passed + * @end_timestamp it returns 0. Beware, NMPlatformIPAddress treats a @lifetime + * of 0 as permanent. + */ + if (end_timestamp == NM_PLATFORM_LIFETIME_PERMANENT) + return NM_PLATFORM_LIFETIME_PERMANENT; + if (start_timestamp >= end_timestamp) + return 0; + return end_timestamp - start_timestamp; +} + +/* _timestamp_nl_to_ms: + * @timestamp_nl: a timestamp from ifa_cacheinfo. + * @monotonic_ms: *now* in CLOCK_MONOTONIC. Needed to estimate the current + * uptime and how often timestamp_nl wrapped. + * + * Convert the timestamp from ifa_cacheinfo to CLOCK_MONOTONIC milliseconds. + * The ifa_cacheinfo fields tstamp and cstamp contains timestamps that counts + * with in 1/100th of a second of clock_gettime(CLOCK_MONOTONIC). However, + * the uint32 counter wraps every 497 days of uptime, so we have to compensate + * for that. */ +static gint64 +_timestamp_nl_to_ms (guint32 timestamp_nl, gint64 monotonic_ms) +{ + const gint64 WRAP_INTERVAL = (((gint64) G_MAXUINT32) + 1) * (1000 / 100); + gint64 timestamp_nl_ms; + + /* convert timestamp from 1/100th of a second to msec. */ + timestamp_nl_ms = ((gint64) timestamp_nl) * (1000 / 100); + + /* timestamp wraps every 497 days. Try to compensate for that.*/ + if (timestamp_nl_ms > monotonic_ms) { + /* timestamp_nl_ms is in the future. Truncate it to *now* */ + timestamp_nl_ms = monotonic_ms; + } else if (monotonic_ms >= WRAP_INTERVAL) { + timestamp_nl_ms += (monotonic_ms / WRAP_INTERVAL) * WRAP_INTERVAL; + if (timestamp_nl_ms > monotonic_ms) + timestamp_nl_ms -= WRAP_INTERVAL; + } + + return timestamp_nl_ms; +} + +static guint32 +_rtnl_addr_last_update_time_to_nm (const struct rtnl_addr *rtnladdr) +{ + guint32 last_update_time = rtnl_addr_get_last_update_time ((struct rtnl_addr *) rtnladdr); + struct timespec tp; + gint64 now_nl, now_nm, result; + + /* timestamp is unset. Default to 1. */ + if (!last_update_time) + return 1; + + /* do all the calculations in milliseconds scale */ + + clock_gettime (CLOCK_MONOTONIC, &tp); + now_nm = nm_utils_get_monotonic_timestamp_ms (); + now_nl = (((gint64) tp.tv_sec) * ((gint64) 1000)) + + (tp.tv_nsec / (NM_UTILS_NS_PER_SECOND/1000)); + + result = now_nm - (now_nl - _timestamp_nl_to_ms (last_update_time, now_nl)); + + /* converting the last_update_time into nm_utils_get_monotonic_timestamp_ms() scale is + * a good guess but fails in the following situations: + * + * - If the address existed before start of the process, the timestamp in nm scale would + * be negative or zero. In this case we default to 1. + * - during hibernation, the CLOCK_MONOTONIC/last_update_time drifts from + * nm_utils_get_monotonic_timestamp_ms() scale. + */ + if (result <= 1000) + return 1; + + if (result > now_nm) + return now_nm / 1000; + + return result / 1000; +} + +static void +_init_ip_address_lifetime (NMPlatformIPAddress *address, const struct rtnl_addr *rtnladdr) +{ + guint32 a_valid = rtnl_addr_get_valid_lifetime ((struct rtnl_addr *) rtnladdr); + guint32 a_preferred = rtnl_addr_get_preferred_lifetime ((struct rtnl_addr *) rtnladdr); + + /* the meaning of the valid and preferred lifetimes is different from the + * original meaning. See _rtnl_addr_hack_lifetimes_rel_to_abs(). + * Beware: this function expects hacked rtnl_addr objects. + */ + + if (a_valid == NM_PLATFORM_LIFETIME_PERMANENT && + a_preferred == NM_PLATFORM_LIFETIME_PERMANENT) { + address->timestamp = 0; + address->lifetime = NM_PLATFORM_LIFETIME_PERMANENT; + address->preferred = NM_PLATFORM_LIFETIME_PERMANENT; + return; + } + + /* The valies are hacked and absolute expiry times. They must + * be positive and preferred<=valid. */ + g_assert (a_preferred <= a_valid && + a_valid > 0 && + a_preferred > 0); + + if (a_valid <= 1) { + /* Since we want to have positive @timestamp and @valid != 0, + * we must handle this case special. */ + address->timestamp = 1; + address->lifetime = 1; /* Extend the lifetime by one second */ + address->preferred = 0; /* no longer preferred. */ + return; + } + + /* _rtnl_addr_last_update_time_to_nm() might be wrong, so don't rely on + * timestamp to have any meaning beyond anchoring the relative durations + * @lifetime and @preferred. + */ + address->timestamp = _rtnl_addr_last_update_time_to_nm (rtnladdr); + + /* We would expect @timestamp to be less then @a_valid. Just to be sure, + * fix it up. */ + address->timestamp = MIN (address->timestamp, a_valid - 1); + address->lifetime = _get_remaining_time (address->timestamp, a_valid); + address->preferred = _get_remaining_time (address->timestamp, a_preferred); +} + +static gboolean +init_ip4_address (NMPlatformIP4Address *address, struct rtnl_addr *rtnladdr) +{ + struct nl_addr *nladdr = rtnl_addr_get_local (rtnladdr); + struct nl_addr *nlpeer = rtnl_addr_get_peer (rtnladdr); + const char *label; + + g_return_val_if_fail (nladdr, FALSE); + + memset (address, 0, sizeof (*address)); + + address->source = NM_PLATFORM_SOURCE_KERNEL; + address->ifindex = rtnl_addr_get_ifindex (rtnladdr); + address->plen = rtnl_addr_get_prefixlen (rtnladdr); + _init_ip_address_lifetime ((NMPlatformIPAddress *) address, rtnladdr); + if (!nladdr || nl_addr_get_len (nladdr) != sizeof (address->address)) { + g_return_val_if_reached (FALSE); + return FALSE; + } + memcpy (&address->address, nl_addr_get_binary_addr (nladdr), sizeof (address->address)); + if (nlpeer) { + if (nl_addr_get_len (nlpeer) != sizeof (address->peer_address)) { + g_return_val_if_reached (FALSE); + return FALSE; + } + memcpy (&address->peer_address, nl_addr_get_binary_addr (nlpeer), sizeof (address->peer_address)); + } + label = rtnl_addr_get_label (rtnladdr); + /* Check for ':'; we're only interested in labels used as interface aliases */ + if (label && strchr (label, ':')) + g_strlcpy (address->label, label, sizeof (address->label)); + + return TRUE; +} + +static gboolean +init_ip6_address (NMPlatformIP6Address *address, struct rtnl_addr *rtnladdr) +{ + struct nl_addr *nladdr = rtnl_addr_get_local (rtnladdr); + struct nl_addr *nlpeer = rtnl_addr_get_peer (rtnladdr); + + memset (address, 0, sizeof (*address)); + + address->source = NM_PLATFORM_SOURCE_KERNEL; + address->ifindex = rtnl_addr_get_ifindex (rtnladdr); + address->plen = rtnl_addr_get_prefixlen (rtnladdr); + _init_ip_address_lifetime ((NMPlatformIPAddress *) address, rtnladdr); + address->flags = rtnl_addr_get_flags (rtnladdr); + if (!nladdr || nl_addr_get_len (nladdr) != sizeof (address->address)) { + g_return_val_if_reached (FALSE); + return FALSE; + } + memcpy (&address->address, nl_addr_get_binary_addr (nladdr), sizeof (address->address)); + if (nlpeer) { + if (nl_addr_get_len (nlpeer) != sizeof (address->peer_address)) { + g_return_val_if_reached (FALSE); + return FALSE; + } + memcpy (&address->peer_address, nl_addr_get_binary_addr (nlpeer), sizeof (address->peer_address)); + } + + return TRUE; +} + +static guint +source_to_rtprot (NMPlatformSource source) +{ + switch (source) { + case NM_PLATFORM_SOURCE_UNKNOWN: + return RTPROT_UNSPEC; + case NM_PLATFORM_SOURCE_KERNEL: + return RTPROT_KERNEL; + case NM_PLATFORM_SOURCE_DHCP: + return RTPROT_DHCP; + case NM_PLATFORM_SOURCE_RDISC: + return RTPROT_RA; + + default: + return RTPROT_STATIC; + } +} + +static NMPlatformSource +rtprot_to_source (guint rtprot) +{ + switch (rtprot) { + case RTPROT_UNSPEC: + return NM_PLATFORM_SOURCE_UNKNOWN; + case RTPROT_REDIRECT: + case RTPROT_KERNEL: + return NM_PLATFORM_SOURCE_KERNEL; + case RTPROT_RA: + return NM_PLATFORM_SOURCE_RDISC; + case RTPROT_DHCP: + return NM_PLATFORM_SOURCE_DHCP; + + default: + return NM_PLATFORM_SOURCE_USER; + } +} + +static gboolean +init_ip4_route (NMPlatformIP4Route *route, struct rtnl_route *rtnlroute) +{ + struct nl_addr *dst, *gw; + struct rtnl_nexthop *nexthop; + + memset (route, 0, sizeof (*route)); + + /* Multi-hop routes not supported. */ + if (rtnl_route_get_nnexthops (rtnlroute) != 1) + return FALSE; + + nexthop = rtnl_route_nexthop_n (rtnlroute, 0); + dst = rtnl_route_get_dst (rtnlroute); + gw = rtnl_route_nh_get_gateway (nexthop); + + route->ifindex = rtnl_route_nh_get_ifindex (nexthop); + route->plen = nl_addr_get_prefixlen (dst); + /* Workaround on previous workaround for libnl default route prefixlen bug. */ + if (nl_addr_get_len (dst)) { + if (nl_addr_get_len (dst) != sizeof (route->network)) { + g_return_val_if_reached (FALSE); + return FALSE; + } + memcpy (&route->network, nl_addr_get_binary_addr (dst), sizeof (route->network)); + } + if (gw) { + if (nl_addr_get_len (gw) != sizeof (route->network)) { + g_return_val_if_reached (FALSE); + return FALSE; + } + memcpy (&route->gateway, nl_addr_get_binary_addr (gw), sizeof (route->gateway)); + } + route->metric = rtnl_route_get_priority (rtnlroute); + rtnl_route_get_metric (rtnlroute, RTAX_ADVMSS, &route->mss); + route->source = rtprot_to_source (rtnl_route_get_protocol (rtnlroute)); + + return TRUE; +} + +static gboolean +init_ip6_route (NMPlatformIP6Route *route, struct rtnl_route *rtnlroute) +{ + struct nl_addr *dst, *gw; + struct rtnl_nexthop *nexthop; + + memset (route, 0, sizeof (*route)); + + /* Multi-hop routes not supported. */ + if (rtnl_route_get_nnexthops (rtnlroute) != 1) + return FALSE; + + nexthop = rtnl_route_nexthop_n (rtnlroute, 0); + dst = rtnl_route_get_dst (rtnlroute); + gw = rtnl_route_nh_get_gateway (nexthop); + + route->ifindex = rtnl_route_nh_get_ifindex (nexthop); + route->plen = nl_addr_get_prefixlen (dst); + /* Workaround on previous workaround for libnl default route prefixlen bug. */ + if (nl_addr_get_len (dst)) { + if (nl_addr_get_len (dst) != sizeof (route->network)) { + g_return_val_if_reached (FALSE); + return FALSE; + } + memcpy (&route->network, nl_addr_get_binary_addr (dst), sizeof (route->network)); + } + if (gw) { + if (nl_addr_get_len (gw) != sizeof (route->network)) { + g_return_val_if_reached (FALSE); + return FALSE; + } + memcpy (&route->gateway, nl_addr_get_binary_addr (gw), sizeof (route->gateway)); + } + route->metric = rtnl_route_get_priority (rtnlroute); + rtnl_route_get_metric (rtnlroute, RTAX_ADVMSS, &route->mss); + route->source = rtprot_to_source (rtnl_route_get_protocol (rtnlroute)); + + return TRUE; +} + +static char to_string_buffer[255]; + +#define SET_AND_RETURN_STRING_BUFFER(...) \ + G_STMT_START { \ + g_snprintf (to_string_buffer, sizeof (to_string_buffer), ## __VA_ARGS__); \ + g_return_val_if_reached (to_string_buffer); \ + return to_string_buffer; \ + } G_STMT_END + +static const char * +to_string_link (NMPlatform *platform, struct rtnl_link *obj) +{ + NMPlatformLink pl_obj; + + if (init_link (platform, &pl_obj, obj)) + return nm_platform_link_to_string (&pl_obj); + SET_AND_RETURN_STRING_BUFFER ("(invalid link %p)", obj); +} + +static const char * +to_string_ip4_address (struct rtnl_addr *obj) +{ + NMPlatformIP4Address pl_obj; + + if (init_ip4_address (&pl_obj, obj)) + return nm_platform_ip4_address_to_string (&pl_obj); + SET_AND_RETURN_STRING_BUFFER ("(invalid ip4 address %p)", obj); +} + +static const char * +to_string_ip6_address (struct rtnl_addr *obj) +{ + NMPlatformIP6Address pl_obj; + + if (init_ip6_address (&pl_obj, obj)) + return nm_platform_ip6_address_to_string (&pl_obj); + SET_AND_RETURN_STRING_BUFFER ("(invalid ip6 address %p)", obj); +} + +static const char * +to_string_ip4_route (struct rtnl_route *obj) +{ + NMPlatformIP4Route pl_obj; + + if (init_ip4_route (&pl_obj, obj)) + return nm_platform_ip4_route_to_string (&pl_obj); + SET_AND_RETURN_STRING_BUFFER ("(invalid ip4 route %p)", obj); +} + +static const char * +to_string_ip6_route (struct rtnl_route *obj) +{ + NMPlatformIP6Route pl_obj; + + if (init_ip6_route (&pl_obj, obj)) + return nm_platform_ip6_route_to_string (&pl_obj); + SET_AND_RETURN_STRING_BUFFER ("(invalid ip6 route %p)", obj); +} + +static const char * +to_string_object_with_type (NMPlatform *platform, struct nl_object *obj, ObjectType type) +{ + switch (type) { + case OBJECT_TYPE_LINK: + return to_string_link (platform, (struct rtnl_link *) obj); + case OBJECT_TYPE_IP4_ADDRESS: + return to_string_ip4_address ((struct rtnl_addr *) obj); + case OBJECT_TYPE_IP6_ADDRESS: + return to_string_ip6_address ((struct rtnl_addr *) obj); + case OBJECT_TYPE_IP4_ROUTE: + return to_string_ip4_route ((struct rtnl_route *) obj); + case OBJECT_TYPE_IP6_ROUTE: + return to_string_ip6_route ((struct rtnl_route *) obj); + default: + SET_AND_RETURN_STRING_BUFFER ("(unknown netlink object %p)", obj); + } +} + +static const char * +to_string_object (NMPlatform *platform, struct nl_object *obj) +{ + return to_string_object_with_type (platform, obj, object_type_from_nl_object (obj)); +} + +#undef SET_AND_RETURN_STRING_BUFFER + +/******************************************************************/ + +/* Object and cache manipulation */ + +static const char *signal_by_type_and_status[__OBJECT_TYPE_LAST] = { + [OBJECT_TYPE_LINK] = NM_PLATFORM_SIGNAL_LINK_CHANGED, + [OBJECT_TYPE_IP4_ADDRESS] = NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, + [OBJECT_TYPE_IP6_ADDRESS] = NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, + [OBJECT_TYPE_IP4_ROUTE] = NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, + [OBJECT_TYPE_IP6_ROUTE] = NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, +}; + +static struct nl_cache * +choose_cache_by_type (NMPlatform *platform, ObjectType object_type) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + + switch (object_type) { + case OBJECT_TYPE_LINK: + return priv->link_cache; + case OBJECT_TYPE_IP4_ADDRESS: + case OBJECT_TYPE_IP6_ADDRESS: + return priv->address_cache; + case OBJECT_TYPE_IP4_ROUTE: + case OBJECT_TYPE_IP6_ROUTE: + return priv->route_cache; + default: + g_return_val_if_reached (NULL); + return NULL; + } +} + +static struct nl_cache * +choose_cache (NMPlatform *platform, struct nl_object *object) +{ + return choose_cache_by_type (platform, object_type_from_nl_object (object)); +} + +static gboolean +object_has_ifindex (struct nl_object *object, int ifindex) +{ + switch (object_type_from_nl_object (object)) { + case OBJECT_TYPE_IP4_ADDRESS: + case OBJECT_TYPE_IP6_ADDRESS: + return ifindex == rtnl_addr_get_ifindex ((struct rtnl_addr *) object); + case OBJECT_TYPE_IP4_ROUTE: + case OBJECT_TYPE_IP6_ROUTE: + { + struct rtnl_route *rtnlroute = (struct rtnl_route *) object; + struct rtnl_nexthop *nexthop; + + if (rtnl_route_get_nnexthops (rtnlroute) != 1) + return FALSE; + nexthop = rtnl_route_nexthop_n (rtnlroute, 0); + + return ifindex == rtnl_route_nh_get_ifindex (nexthop); + } + default: + g_assert_not_reached (); + } +} + +static gboolean refresh_object (NMPlatform *platform, struct nl_object *object, gboolean removed, NMPlatformReason reason); + +static void +check_cache_items (NMPlatform *platform, struct nl_cache *cache, int ifindex) +{ + auto_nl_cache struct nl_cache *cloned_cache = nl_cache_clone (cache); + struct nl_object *object; + GPtrArray *objects_to_refresh = g_ptr_array_new_with_free_func ((GDestroyNotify) nl_object_put); + guint i; + + for (object = nl_cache_get_first (cloned_cache); object; object = nl_cache_get_next (object)) { + if (object_has_ifindex (object, ifindex)) { + nl_object_get (object); + g_ptr_array_add (objects_to_refresh, object); + } + } + + for (i = 0; i < objects_to_refresh->len; i++) + refresh_object (platform, objects_to_refresh->pdata[i], TRUE, NM_PLATFORM_REASON_CACHE_CHECK); + + g_ptr_array_free (objects_to_refresh, TRUE); +} + +static void +announce_object (NMPlatform *platform, const struct nl_object *object, NMPlatformSignalChangeType change_type, NMPlatformReason reason) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + ObjectType object_type = object_type_from_nl_object (object); + const char *sig = signal_by_type_and_status[object_type]; + + switch (object_type) { + case OBJECT_TYPE_LINK: + { + NMPlatformLink device; + struct rtnl_link *rtnl_link = (struct rtnl_link *) object; + + if (!init_link (platform, &device, rtnl_link)) + return; + + /* Skip hardware devices not yet discovered by udev. They will be + * announced by udev_device_added(). This doesn't apply to removed + * devices, as those come either from udev_device_removed(), + * event_notification() or link_delete() which block the announcment + * themselves when appropriate. + */ + switch (change_type) { + case NM_PLATFORM_SIGNAL_ADDED: + case NM_PLATFORM_SIGNAL_CHANGED: + if (!link_is_software (rtnl_link) && !device.driver) + return; + break; + default: + break; + } + + /* Link deletion or setting down is sometimes accompanied by address + * and/or route deletion. + * + * More precisely, kernel removes routes when interface goes !IFF_UP and + * removes both addresses and routes when interface is removed. + */ + switch (change_type) { + case NM_PLATFORM_SIGNAL_CHANGED: + if (!device.connected) + check_cache_items (platform, priv->route_cache, device.ifindex); + break; + case NM_PLATFORM_SIGNAL_REMOVED: + check_cache_items (platform, priv->address_cache, device.ifindex); + check_cache_items (platform, priv->route_cache, device.ifindex); + g_hash_table_remove (priv->wifi_data, GINT_TO_POINTER (device.ifindex)); + break; + default: + break; + } + + g_signal_emit_by_name (platform, sig, device.ifindex, &device, change_type, reason); + } + return; + case OBJECT_TYPE_IP4_ADDRESS: + { + NMPlatformIP4Address address; + + if (!init_ip4_address (&address, (struct rtnl_addr *) object)) + return; + + /* Address deletion is sometimes accompanied by route deletion. We need to + * check all routes belonging to the same interface. + */ + switch (change_type) { + case NM_PLATFORM_SIGNAL_REMOVED: + check_cache_items (platform, priv->route_cache, address.ifindex); + break; + default: + break; + } + + g_signal_emit_by_name (platform, sig, address.ifindex, &address, change_type, reason); + } + return; + case OBJECT_TYPE_IP6_ADDRESS: + { + NMPlatformIP6Address address; + + if (!init_ip6_address (&address, (struct rtnl_addr *) object)) + return; + g_signal_emit_by_name (platform, sig, address.ifindex, &address, change_type, reason); + } + return; + case OBJECT_TYPE_IP4_ROUTE: + { + NMPlatformIP4Route route; + + if (init_ip4_route (&route, (struct rtnl_route *) object)) + g_signal_emit_by_name (platform, sig, route.ifindex, &route, change_type, reason); + } + return; + case OBJECT_TYPE_IP6_ROUTE: + { + NMPlatformIP6Route route; + + if (init_ip6_route (&route, (struct rtnl_route *) object)) + g_signal_emit_by_name (platform, sig, route.ifindex, &route, change_type, reason); + } + return; + default: + g_return_if_reached (); + } +} + +static struct nl_object * build_rtnl_link (int ifindex, const char *name, NMLinkType type); + +static gboolean +refresh_object (NMPlatform *platform, struct nl_object *object, gboolean removed, NMPlatformReason reason) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + auto_nl_object struct nl_object *cached_object = NULL; + auto_nl_object struct nl_object *kernel_object = NULL; + struct nl_cache *cache; + int nle; + + cache = choose_cache (platform, object); + cached_object = nm_nl_cache_search (cache, object); + kernel_object = get_kernel_object (priv->nlh, object); + + if (removed) { + if (kernel_object) + return TRUE; + + /* Only announce object if it was still in the cache. */ + if (cached_object) { + nl_cache_remove (cached_object); + + announce_object (platform, cached_object, NM_PLATFORM_SIGNAL_REMOVED, reason); + } + } else { + if (!kernel_object) + return FALSE; + + hack_empty_master_iff_lower_up (platform, kernel_object); + + if (cached_object) + nl_cache_remove (cached_object); + nle = nl_cache_add (cache, kernel_object); + if (nle) { + nm_log_dbg (LOGD_PLATFORM, "refresh_object(reason %d) failed during nl_cache_add with %d", reason, nle); + return FALSE; + } + + announce_object (platform, kernel_object, cached_object ? NM_PLATFORM_SIGNAL_CHANGED : NM_PLATFORM_SIGNAL_ADDED, reason); + + /* Refresh the master device (even on enslave/release) */ + if (object_type_from_nl_object (kernel_object) == OBJECT_TYPE_LINK) { + int kernel_master = rtnl_link_get_master ((struct rtnl_link *) kernel_object); + int cached_master = cached_object ? rtnl_link_get_master ((struct rtnl_link *) cached_object) : 0; + struct nl_object *master_object; + + if (kernel_master) { + master_object = build_rtnl_link (kernel_master, NULL, NM_LINK_TYPE_NONE); + refresh_object (platform, master_object, FALSE, NM_PLATFORM_REASON_INTERNAL); + nl_object_put (master_object); + } + if (cached_master && cached_master != kernel_master) { + master_object = build_rtnl_link (cached_master, NULL, NM_LINK_TYPE_NONE); + refresh_object (platform, master_object, FALSE, NM_PLATFORM_REASON_INTERNAL); + nl_object_put (master_object); + } + } + } + + return TRUE; +} + +/* Decreases the reference count if @obj for convenience */ +static gboolean +add_object (NMPlatform *platform, struct nl_object *obj) +{ + auto_nl_object struct nl_object *object = obj; + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + int nle; + struct nl_dump_params dp = { + .dp_type = NL_DUMP_DETAILS, + .dp_fd = stderr, + }; + + g_return_val_if_fail (object, FALSE); + + nle = add_kernel_object (priv->nlh, object); + + /* NLE_EXIST is considered equivalent to success to avoid race conditions. You + * never know when something sends an identical object just before + * NetworkManager. + */ + switch (nle) { + case -NLE_SUCCESS: + case -NLE_EXIST: + break; + default: + error ("Netlink error adding %s: %s", to_string_object (platform, object), nl_geterror (nle)); + nl_object_dump (object, &dp); + return FALSE; + } + + return refresh_object (platform, object, FALSE, NM_PLATFORM_REASON_INTERNAL); +} + +/* Decreases the reference count if @obj for convenience */ +static gboolean +delete_object (NMPlatform *platform, struct nl_object *obj, gboolean do_refresh_object) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + auto_nl_object struct nl_object *obj_cleanup = obj; + struct nl_object *object = obj; + int object_type; + int nle; + + object_type = object_type_from_nl_object (obj); + g_return_val_if_fail (object_type != OBJECT_TYPE_UNKNOWN, FALSE); + + switch (object_type) { + case OBJECT_TYPE_LINK: + nle = rtnl_link_delete (priv->nlh, (struct rtnl_link *) object); + break; + case OBJECT_TYPE_IP4_ADDRESS: + case OBJECT_TYPE_IP6_ADDRESS: + nle = rtnl_addr_delete (priv->nlh, (struct rtnl_addr *) object, 0); + break; + case OBJECT_TYPE_IP4_ROUTE: + case OBJECT_TYPE_IP6_ROUTE: + nle = rtnl_route_delete (priv->nlh, (struct rtnl_route *) object, 0); + break; + default: + g_assert_not_reached (); + } + + switch (nle) { + case -NLE_SUCCESS: + break; + case -NLE_OBJ_NOTFOUND: + debug("delete_object failed with \"%s\" (%d), meaning the object was already removed", + nl_geterror (nle), nle); + break; + case -NLE_FAILURE: + if (object_type == OBJECT_TYPE_IP6_ADDRESS) { + /* On RHEL7 kernel, deleting a non existing address fails with ENXIO (which libnl maps to NLE_FAILURE) */ + debug("delete_object for address failed with \"%s\" (%d), meaning the address was already removed", + nl_geterror (nle), nle); + break; + } + goto DEFAULT; + case -NLE_NOADDR: + if (object_type == OBJECT_TYPE_IP4_ADDRESS || object_type == OBJECT_TYPE_IP6_ADDRESS) { + debug("delete_object for address failed with \"%s\" (%d), meaning the address was already removed", + nl_geterror (nle), nle); + break; + } + goto DEFAULT; + DEFAULT: + default: + error ("Netlink error deleting %s: %s (%d)", to_string_object (platform, obj), nl_geterror (nle), nle); + return FALSE; + } + + if (do_refresh_object) + refresh_object (platform, object, TRUE, NM_PLATFORM_REASON_INTERNAL); + + return TRUE; +} + +static void +ref_object (struct nl_object *obj, void *data) +{ + struct nl_object **out = data; + + nl_object_get (obj); + *out = obj; +} + +static gboolean +_rtnl_addr_timestamps_equal_fuzzy (guint32 ts1, guint32 ts2) +{ + guint32 diff; + + if (ts1 == ts2) + return TRUE; + if (ts1 == NM_PLATFORM_LIFETIME_PERMANENT || + ts2 == NM_PLATFORM_LIFETIME_PERMANENT) + return FALSE; + + /** accept the timestamps as equal if they are within two seconds. */ + diff = ts1 > ts2 ? ts1 - ts2 : ts2 - ts1; + return diff <= 2; +} + +/* This function does all the magic to avoid race conditions caused + * by concurrent usage of synchronous commands and an asynchronous cache. This + * might be a nice future addition to libnl but it requires to do all operations + * through the cache manager. In this case, nm-linux-platform serves as the + * cache manager instead of the one provided by libnl. + */ +static int +event_notification (struct nl_msg *msg, gpointer user_data) +{ + NMPlatform *platform = NM_PLATFORM (user_data); + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + struct nl_cache *cache; + auto_nl_object struct nl_object *object = NULL; + auto_nl_object struct nl_object *cached_object = NULL; + auto_nl_object struct nl_object *kernel_object = NULL; + int event; + int nle; + ObjectType type; + + event = nlmsg_hdr (msg)->nlmsg_type; + + if (priv->support_kernel_extended_ifa_flags == 0 && event == RTM_NEWADDR) { + /* if kernel support for extended ifa flags is still undecided, use the opportunity + * now and use @msg to decide it. This saves a blocking net link request. + **/ + _check_support_kernel_extended_ifa_flags_init (priv, msg); + } + + nl_msg_parse (msg, ref_object, &object); + g_return_val_if_fail (object, NL_OK); + + type = object_type_from_nl_object (object); + + if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) { + if (type == OBJECT_TYPE_LINK) { + const char *name = rtnl_link_get_name ((struct rtnl_link *) object); + + debug ("netlink event (type %d) for link: %s (%d, family %d)", + event, name ? name : "(unknown)", + rtnl_link_get_ifindex ((struct rtnl_link *) object), + rtnl_link_get_family ((struct rtnl_link *) object)); + } else + debug ("netlink event (type %d)", event); + } + + cache = choose_cache_by_type (platform, type); + cached_object = nm_nl_cache_search (cache, object); + kernel_object = get_kernel_object (priv->nlh, object); + + hack_empty_master_iff_lower_up (platform, kernel_object); + + /* Removed object */ + switch (event) { + case RTM_DELLINK: + case RTM_DELADDR: + case RTM_DELROUTE: + /* Ignore inconsistent deletion + * + * Quick external deletion and addition can be occasionally + * seen as just a change. + */ + if (kernel_object) + return NL_OK; + /* Ignore internal deletion */ + if (!cached_object) + return NL_OK; + + nl_cache_remove (cached_object); + /* Don't announce removed interfaces that are not recognized by + * udev. They were either not yet discovered or they have been + * already removed and announced. + */ + if (event == RTM_DELLINK) { + if (!link_is_announceable (platform, (struct rtnl_link *) cached_object)) + return NL_OK; + } + announce_object (platform, cached_object, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_EXTERNAL); + + return NL_OK; + case RTM_NEWLINK: + case RTM_NEWADDR: + case RTM_NEWROUTE: + /* Ignore inconsistent addition or change (kernel will send a good one) + * + * Quick sequence of RTM_NEWLINK notifications can be occasionally + * collapsed to just one addition or deletion, depending of whether we + * already have the object in cache. + */ + if (!kernel_object) + return NL_OK; + /* Handle external addition */ + if (!cached_object) { + nle = nl_cache_add (cache, kernel_object); + if (nle) { + error ("netlink cache error: %s", nl_geterror (nle)); + return NL_OK; + } + announce_object (platform, kernel_object, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_EXTERNAL); + return NL_OK; + } + /* Ignore non-change + * + * This also catches notifications for internal addition or change, unless + * another action occured very soon after it. + */ + if (!nl_object_diff (kernel_object, cached_object)) { + if (type == OBJECT_TYPE_IP4_ADDRESS || type == OBJECT_TYPE_IP6_ADDRESS) { + struct rtnl_addr *c = (struct rtnl_addr *) cached_object; + struct rtnl_addr *k = (struct rtnl_addr *) kernel_object; + + /* libnl nl_object_diff() ignores differences in timestamp. Let's care about + * them (if they are large enough). + * + * Note that these valid and preferred timestamps are absolute, after + * _rtnl_addr_hack_lifetimes_rel_to_abs(). */ + if ( _rtnl_addr_timestamps_equal_fuzzy (rtnl_addr_get_preferred_lifetime (c), + rtnl_addr_get_preferred_lifetime (k)) + && _rtnl_addr_timestamps_equal_fuzzy (rtnl_addr_get_valid_lifetime (c), + rtnl_addr_get_valid_lifetime (k))) + return NL_OK; + } else + return NL_OK; + } + /* Handle external change */ + nl_cache_remove (cached_object); + nle = nl_cache_add (cache, kernel_object); + if (nle) { + error ("netlink cache error: %s", nl_geterror (nle)); + return NL_OK; + } + announce_object (platform, kernel_object, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_EXTERNAL); + + return NL_OK; + default: + error ("Unknown netlink event: %d", event); + return NL_OK; + } +} + +/******************************************************************/ + +static void +_log_dbg_sysctl_set_impl (const char *path, const char *value) +{ + GError *error = NULL; + char *contents, *contents_escaped; + char *value_escaped = g_strescape (value, NULL); + + if (!g_file_get_contents (path, &contents, NULL, &error)) { + debug ("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", path, value_escaped, error->message); + g_clear_error (&error); + } else { + g_strstrip (contents); + contents_escaped = g_strescape (contents, NULL); + if (strcmp (contents, value) == 0) + debug ("sysctl: setting '%s' to '%s' (current value is identical)", path, value_escaped); + else + debug ("sysctl: setting '%s' to '%s' (current value is '%s')", path, value_escaped, contents_escaped); + g_free (contents); + g_free (contents_escaped); + } + g_free (value_escaped); +} + +#define _log_dbg_sysctl_set(path, value) \ + G_STMT_START { \ + if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) { \ + _log_dbg_sysctl_set_impl (path, value); \ + } \ + } G_STMT_END + +static gboolean +sysctl_set (NMPlatform *platform, const char *path, const char *value) +{ + int fd, len, nwrote, tries; + char *actual; + + g_return_val_if_fail (path != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + /* Don't write outside known locations */ + g_assert (g_str_has_prefix (path, "/proc/sys/") + || g_str_has_prefix (path, "/sys/")); + /* Don't write to suspicious locations */ + g_assert (!strstr (path, "/../")); + + fd = open (path, O_WRONLY | O_TRUNC); + if (fd == -1) { + if (errno == ENOENT) { + debug ("sysctl: failed to open '%s': (%d) %s", + path, errno, strerror (errno)); + } else { + error ("sysctl: failed to open '%s': (%d) %s", + path, errno, strerror (errno)); + } + return FALSE; + } + + _log_dbg_sysctl_set (path, value); + + /* Most sysfs and sysctl options don't care about a trailing LF, while some + * (like infiniband) do. So always add the LF. Also, neither sysfs nor + * sysctl support partial writes so the LF must be added to the string we're + * about to write. + */ + actual = g_strdup_printf ("%s\n", value); + + /* Try to write the entire value three times if a partial write occurs */ + len = strlen (actual); + for (tries = 0, nwrote = 0; tries < 3 && nwrote != len; tries++) { + nwrote = write (fd, actual, len); + if (nwrote == -1) { + if (errno == EINTR) { + debug ("sysctl: interrupted, will try again"); + continue; + } + break; + } + } + if (nwrote == -1 && errno != EEXIST) { + error ("sysctl: failed to set '%s' to '%s': (%d) %s", + path, value, errno, strerror (errno)); + } else if (nwrote < len) { + error ("sysctl: failed to set '%s' to '%s' after three attempts", + path, value); + } + + g_free (actual); + close (fd); + return (nwrote == len); +} + +static GHashTable *sysctl_get_prev_values; + +static void +_log_dbg_sysctl_get_impl (const char *path, const char *contents) +{ + const char *prev_value = NULL; + + if (!sysctl_get_prev_values) + sysctl_get_prev_values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + else + prev_value = g_hash_table_lookup (sysctl_get_prev_values, path); + + if (prev_value) { + if (strcmp (prev_value, contents) != 0) { + char *contents_escaped = g_strescape (contents, NULL); + char *prev_value_escaped = g_strescape (prev_value, NULL); + + debug ("sysctl: reading '%s': '%s' (changed from '%s' on last read)", path, contents_escaped, prev_value_escaped); + g_free (contents_escaped); + g_free (prev_value_escaped); + g_hash_table_insert (sysctl_get_prev_values, g_strdup (path), g_strdup (contents)); + } + } else { + char *contents_escaped = g_strescape (contents, NULL); + + debug ("sysctl: reading '%s': '%s'", path, contents_escaped); + g_free (contents_escaped); + g_hash_table_insert (sysctl_get_prev_values, g_strdup (path), g_strdup (contents)); + } +} + +#define _log_dbg_sysctl_get(path, contents) \ + G_STMT_START { \ + if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) { \ + _log_dbg_sysctl_get_impl (path, contents); \ + } else if (sysctl_get_prev_values) { \ + g_hash_table_destroy (sysctl_get_prev_values); \ + sysctl_get_prev_values = NULL; \ + } \ + } G_STMT_END + +static char * +sysctl_get (NMPlatform *platform, const char *path) +{ + GError *error = NULL; + char *contents; + + /* Don't write outside known locations */ + g_assert (g_str_has_prefix (path, "/proc/sys/") + || g_str_has_prefix (path, "/sys/")); + /* Don't write to suspicious locations */ + g_assert (!strstr (path, "/../")); + + if (!g_file_get_contents (path, &contents, NULL, &error)) { + /* We assume FAILED means EOPNOTSUP */ + if ( g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT) + || g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_FAILED)) + debug ("error reading %s: %s", path, error->message); + else + error ("error reading %s: %s", path, error->message); + g_clear_error (&error); + return NULL; + } + + g_strstrip (contents); + + _log_dbg_sysctl_get (path, contents); + + return contents; +} + +/******************************************************************/ + +static GArray * +link_get_all (NMPlatform *platform) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + GArray *links = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformLink), nl_cache_nitems (priv->link_cache)); + NMPlatformLink device; + struct nl_object *object; + + for (object = nl_cache_get_first (priv->link_cache); object; object = nl_cache_get_next (object)) { + struct rtnl_link *rtnl_link = (struct rtnl_link *) object; + + if (link_is_announceable (platform, rtnl_link)) { + if (init_link (platform, &device, rtnl_link)) + g_array_append_val (links, device); + } + } + + return links; +} + +static gboolean +_nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *link) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + auto_nl_object struct rtnl_link *rtnllink = NULL; + + rtnllink = rtnl_link_get (priv->link_cache, ifindex); + if (rtnllink) { + if (link_is_announceable (platform, rtnllink)) { + if (init_link (platform, link, rtnllink)) + return TRUE; + } + } + return FALSE; +} + +static struct nl_object * +build_rtnl_link (int ifindex, const char *name, NMLinkType type) +{ + struct rtnl_link *rtnllink; + int nle; + + rtnllink = _nm_rtnl_link_alloc (ifindex, name); + if (type) { + nle = rtnl_link_set_type (rtnllink, type_to_string (type)); + g_assert (!nle); + } + return (struct nl_object *) rtnllink; +} + +static gboolean +link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len) +{ + int r; + struct nl_object *link; + + if (type == NM_LINK_TYPE_BOND) { + /* When the kernel loads the bond module, either via explicit modprobe + * or automatically in response to creating a bond master, it will also + * create a 'bond0' interface. Since the bond we're about to create may + * or may not be named 'bond0' prevent potential confusion about a bond + * that the user didn't want by telling the bonding module not to create + * bond0 automatically. + */ + if (!g_file_test ("/sys/class/net/bonding_masters", G_FILE_TEST_EXISTS)) + /* Ignore return value to shut up the compiler */ + r = system ("modprobe bonding max_bonds=0"); + } + + debug ("link: add link '%s' of type '%s' (%d)", + name, type_to_string (type), (int) type); + + link = build_rtnl_link (0, name, type); + + g_assert ( (address != NULL) ^ (address_len == 0) ); + if (address) { + auto_nl_addr struct nl_addr *nladdr = _nm_nl_addr_build (AF_LLC, address, address_len); + + rtnl_link_set_addr ((struct rtnl_link *) link, nladdr); + } + return add_object (platform, link); +} + +static struct rtnl_link * +link_get (NMPlatform *platform, int ifindex) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + struct rtnl_link *rtnllink = rtnl_link_get (priv->link_cache, ifindex); + + if (!rtnllink) { + platform->error = NM_PLATFORM_ERROR_NOT_FOUND; + return NULL; + } + + /* physical interfaces must be found by udev before they can be used */ + if (!link_is_announceable (platform, rtnllink)) { + platform->error = NM_PLATFORM_ERROR_NOT_FOUND; + rtnl_link_put (rtnllink); + return NULL; + } + + return rtnllink; +} + +static gboolean +link_change (NMPlatform *platform, int ifindex, struct rtnl_link *change) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex); + int nle; + + if (!rtnllink) + return FALSE; + g_return_val_if_fail (rtnl_link_get_ifindex (change) > 0, FALSE); + + nle = rtnl_link_change (priv->nlh, rtnllink, change, 0); + + /* NLE_EXIST is considered equivalent to success to avoid race conditions. You + * never know when something sends an identical object just before + * NetworkManager. + * + * When netlink returns NLE_OBJ_NOTFOUND, it usually means it failed to find + * firmware for the device, especially on nm_platform_link_set_up (). + * This is basically the same check as in the original code and could + * potentially be improved. + */ + switch (nle) { + case -NLE_SUCCESS: + case -NLE_EXIST: + break; + case -NLE_OBJ_NOTFOUND: + error ("Firmware not found for changing link %s; Netlink error: %s)", to_string_link (platform, change), nl_geterror (nle)); + platform->error = NM_PLATFORM_ERROR_NO_FIRMWARE; + return FALSE; + default: + error ("Netlink error changing link %s: %s", to_string_link (platform, change), nl_geterror (nle)); + return FALSE; + } + + return refresh_object (platform, (struct nl_object *) rtnllink, FALSE, NM_PLATFORM_REASON_INTERNAL); +} + +static gboolean +link_delete (NMPlatform *platform, int ifindex) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + struct rtnl_link *rtnllink = rtnl_link_get (priv->link_cache, ifindex); + + if (!rtnllink) { + platform->error = NM_PLATFORM_ERROR_NOT_FOUND; + return FALSE; + } + + return delete_object (platform, build_rtnl_link (ifindex, NULL, NM_LINK_TYPE_NONE), TRUE); +} + +static int +link_get_ifindex (NMPlatform *platform, const char *ifname) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + + return rtnl_link_name2i (priv->link_cache, ifname); +} + +static const char * +link_get_name (NMPlatform *platform, int ifindex) +{ + auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex); + + return rtnllink ? rtnl_link_get_name (rtnllink) : NULL; +} + +static NMLinkType +link_get_type (NMPlatform *platform, int ifindex) +{ + auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex); + + return link_extract_type (platform, rtnllink, NULL); +} + +static const char * +link_get_type_name (NMPlatform *platform, int ifindex) +{ + auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex); + const char *type; + + link_extract_type (platform, rtnllink, &type); + return type; +} + +static guint32 +link_get_flags (NMPlatform *platform, int ifindex) +{ + auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex); + + if (!rtnllink) + return IFF_NOARP; + + return rtnl_link_get_flags (rtnllink); +} + +static gboolean +link_refresh (NMPlatform *platform, int ifindex) +{ + auto_nl_object struct rtnl_link *rtnllink = _nm_rtnl_link_alloc (ifindex, NULL); + + return refresh_object (platform, (struct nl_object *) rtnllink, FALSE, NM_PLATFORM_REASON_EXTERNAL); +} + +static gboolean +link_is_up (NMPlatform *platform, int ifindex) +{ + return !!(link_get_flags (platform, ifindex) & IFF_UP); +} + +static gboolean +link_is_connected (NMPlatform *platform, int ifindex) +{ + return !!(link_get_flags (platform, ifindex) & IFF_LOWER_UP); +} + +static gboolean +link_uses_arp (NMPlatform *platform, int ifindex) +{ + return !(link_get_flags (platform, ifindex) & IFF_NOARP); +} + +static gboolean +link_change_flags (NMPlatform *platform, int ifindex, unsigned int flags, gboolean value) +{ + auto_nl_object struct rtnl_link *change = _nm_rtnl_link_alloc (ifindex, NULL); + + if (value) + rtnl_link_set_flags (change, flags); + else + rtnl_link_unset_flags (change, flags); + + if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) { + char buf[512]; + + rtnl_link_flags2str (flags, buf, sizeof (buf)); + debug ("link: change %d: flags %s '%s' (%d)", ifindex, value ? "set" : "unset", buf, flags); + } + + return link_change (platform, ifindex, change); +} + +static gboolean +link_set_up (NMPlatform *platform, int ifindex) +{ + return link_change_flags (platform, ifindex, IFF_UP, TRUE); +} + +static gboolean +link_set_down (NMPlatform *platform, int ifindex) +{ + return link_change_flags (platform, ifindex, IFF_UP, FALSE); +} + +static gboolean +link_set_arp (NMPlatform *platform, int ifindex) +{ + return link_change_flags (platform, ifindex, IFF_NOARP, FALSE); +} + +static gboolean +link_set_noarp (NMPlatform *platform, int ifindex) +{ + return link_change_flags (platform, ifindex, IFF_NOARP, TRUE); +} + +static gboolean +supports_ethtool_carrier_detect (const char *ifname) +{ + struct ethtool_cmd edata = { .cmd = ETHTOOL_GLINK }; + + /* We ignore the result. If the ETHTOOL_GLINK call succeeded, then we + * assume the device supports carrier-detect, otherwise we assume it + * doesn't. + */ + return ethtool_get (ifname, &edata); +} + +static gboolean +supports_mii_carrier_detect (const char *ifname) +{ + int fd; + struct ifreq ifr; + struct mii_ioctl_data *mii; + gboolean supports_mii = FALSE; + + fd = socket (PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + nm_log_err (LOGD_PLATFORM, "couldn't open control socket."); + return FALSE; + } + + memset (&ifr, 0, sizeof (struct ifreq)); + strncpy (ifr.ifr_name, ifname, IFNAMSIZ); + + errno = 0; + if (ioctl (fd, SIOCGMIIPHY, &ifr) < 0) { + nm_log_dbg (LOGD_PLATFORM, "SIOCGMIIPHY failed: %d", errno); + goto out; + } + + /* If we can read the BMSR register, we assume that the card supports MII link detection */ + mii = (struct mii_ioctl_data *) &ifr.ifr_ifru; + mii->reg_num = MII_BMSR; + + if (ioctl (fd, SIOCGMIIREG, &ifr) == 0) { + nm_log_dbg (LOGD_PLATFORM, "SIOCGMIIREG result 0x%X", mii->val_out); + supports_mii = TRUE; + } else { + nm_log_dbg (LOGD_PLATFORM, "SIOCGMIIREG failed: %d", errno); + } + + out: + close (fd); + nm_log_dbg (LOGD_PLATFORM, "MII %s supported", supports_mii ? "is" : "not"); + return supports_mii; +} + +static gboolean +link_supports_carrier_detect (NMPlatform *platform, int ifindex) +{ + const char *name = nm_platform_link_get_name (ifindex); + + if (!name) + return FALSE; + + /* We use netlink for the actual carrier detection, but netlink can't tell + * us whether the device actually supports carrier detection in the first + * place. We assume any device that does implements one of these two APIs. + */ + return supports_ethtool_carrier_detect (name) || supports_mii_carrier_detect (name); +} + +static gboolean +link_supports_vlans (NMPlatform *platform, int ifindex) +{ + auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex); + const char *name = nm_platform_link_get_name (ifindex); + auto_g_free struct ethtool_gfeatures *features = NULL; + int idx, block, bit, size; + + /* Only ARPHRD_ETHER links can possibly support VLANs. */ + if (!rtnllink || rtnl_link_get_arptype (rtnllink) != ARPHRD_ETHER) + return FALSE; + + if (!name) + return FALSE; + + idx = ethtool_get_stringset_index (name, ETH_SS_FEATURES, "vlan-challenged"); + if (idx == -1) { + debug ("vlan-challenged ethtool feature does not exist?"); + return FALSE; + } + + block = idx / 32; + bit = idx % 32; + size = block + 1; + + features = g_malloc0 (sizeof (*features) + size * sizeof (struct ethtool_get_features_block)); + features->cmd = ETHTOOL_GFEATURES; + features->size = size; + + if (!ethtool_get (name, features)) + return FALSE; + + return !(features->features[block].active & (1 << bit)); +} + +static gboolean +link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size_t length) +{ + auto_nl_object struct rtnl_link *change = _nm_rtnl_link_alloc (ifindex, NULL); + auto_nl_addr struct nl_addr *nladdr = _nm_nl_addr_build (AF_LLC, address, length); + + rtnl_link_set_addr (change, nladdr); + + if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) { + char *mac = nm_utils_hwaddr_ntoa_len (address, length); + + debug ("link: change %d: address %s (%lu bytes)", ifindex, mac, (unsigned long) length); + g_free (mac); + } + + return link_change (platform, ifindex, change); +} + +static gconstpointer +link_get_address (NMPlatform *platform, int ifindex, size_t *length) +{ + auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex); + struct nl_addr *nladdr; + + nladdr = rtnllink ? rtnl_link_get_addr (rtnllink) : NULL; + + if (length) + *length = nladdr ? nl_addr_get_len (nladdr) : 0; + + return nladdr ? nl_addr_get_binary_addr (nladdr) : NULL; +} + +static gboolean +link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu) +{ + auto_nl_object struct rtnl_link *change = _nm_rtnl_link_alloc (ifindex, NULL); + + rtnl_link_set_mtu (change, mtu); + debug ("link: change %d: mtu %lu", ifindex, (unsigned long)mtu); + + return link_change (platform, ifindex, change); +} + +static guint32 +link_get_mtu (NMPlatform *platform, int ifindex) +{ + auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex); + + return rtnllink ? rtnl_link_get_mtu (rtnllink) : 0; +} + +static char * +link_get_physical_port_id (NMPlatform *platform, int ifindex) +{ + const char *ifname; + char *path, *id; + + ifname = nm_platform_link_get_name (ifindex); + if (!ifname) + return NULL; + + ifname = ASSERT_VALID_PATH_COMPONENT (ifname); + + path = g_strdup_printf ("/sys/class/net/%s/phys_port_id", ifname); + id = sysctl_get (platform, path); + g_free (path); + + return id; +} + +static int +vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags) +{ + struct nl_object *object = build_rtnl_link (0, name, NM_LINK_TYPE_VLAN); + struct rtnl_link *rtnllink = (struct rtnl_link *) object; + unsigned int kernel_flags; + + kernel_flags = 0; + if (vlan_flags & NM_VLAN_FLAG_REORDER_HEADERS) + kernel_flags |= VLAN_FLAG_REORDER_HDR; + if (vlan_flags & NM_VLAN_FLAG_GVRP) + kernel_flags |= VLAN_FLAG_GVRP; + if (vlan_flags & NM_VLAN_FLAG_LOOSE_BINDING) + kernel_flags |= VLAN_FLAG_LOOSE_BINDING; + + rtnl_link_set_link (rtnllink, parent); + rtnl_link_vlan_set_id (rtnllink, vlan_id); + rtnl_link_vlan_set_flags (rtnllink, kernel_flags); + + debug ("link: add vlan '%s', parent %d, vlan id %d, flags %X (native: %X)", + name, parent, vlan_id, (unsigned int) vlan_flags, kernel_flags); + + return add_object (platform, object); +} + +static gboolean +vlan_get_info (NMPlatform *platform, int ifindex, int *parent, int *vlan_id) +{ + auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex); + + if (parent) + *parent = rtnllink ? rtnl_link_get_link (rtnllink) : 0; + if (vlan_id) + *vlan_id = rtnllink ? rtnl_link_vlan_get_id (rtnllink) : 0; + + return !!rtnllink; +} + +static gboolean +vlan_set_ingress_map (NMPlatform *platform, int ifindex, int from, int to) +{ + /* We have to use link_get() because a "blank" rtnl_link won't have the + * right data structures to be able to call rtnl_link_vlan_set_ingress_map() + * on it. (Likewise below in vlan_set_egress_map().) + */ + auto_nl_object struct rtnl_link *change = link_get (platform, ifindex); + + if (!change) + return FALSE; + rtnl_link_vlan_set_ingress_map (change, from, to); + + debug ("link: change %d: vlan ingress map %d -> %d", ifindex, from, to); + + return link_change (platform, ifindex, change); +} + +static gboolean +vlan_set_egress_map (NMPlatform *platform, int ifindex, int from, int to) +{ + auto_nl_object struct rtnl_link *change = link_get (platform, ifindex); + + if (!change) + return FALSE; + rtnl_link_vlan_set_egress_map (change, from, to); + + debug ("link: change %d: vlan egress map %d -> %d", ifindex, from, to); + + return link_change (platform, ifindex, change); +} + +static gboolean +link_enslave (NMPlatform *platform, int master, int slave) +{ + auto_nl_object struct rtnl_link *change = _nm_rtnl_link_alloc (slave, NULL); + + rtnl_link_set_master (change, master); + debug ("link: change %d: enslave to master %d", slave, master); + + return link_change (platform, slave, change); +} + +static gboolean +link_release (NMPlatform *platform, int master, int slave) +{ + return link_enslave (platform, 0, slave); +} + +static int +link_get_master (NMPlatform *platform, int slave) +{ + auto_nl_object struct rtnl_link *rtnllink = link_get (platform, slave); + + return rtnllink ? rtnl_link_get_master (rtnllink) : 0; +} + +static char * +link_option_path (int master, const char *category, const char *option) +{ + const char *name = nm_platform_link_get_name (master); + + if (!name || !category || !option) + return NULL; + + return g_strdup_printf ("/sys/class/net/%s/%s/%s", + ASSERT_VALID_PATH_COMPONENT (name), + ASSERT_VALID_PATH_COMPONENT (category), + ASSERT_VALID_PATH_COMPONENT (option)); +} + +static gboolean +link_set_option (int master, const char *category, const char *option, const char *value) +{ + auto_g_free char *path = link_option_path (master, category, option); + + return path && nm_platform_sysctl_set (path, value); +} + +static char * +link_get_option (int master, const char *category, const char *option) +{ + auto_g_free char *path = link_option_path (master, category, option); + + return path ? nm_platform_sysctl_get (path) : NULL; +} + +static const char * +master_category (NMPlatform *platform, int master) +{ + switch (link_get_type (platform, master)) { + case NM_LINK_TYPE_BRIDGE: + return "bridge"; + case NM_LINK_TYPE_BOND: + return "bonding"; + default: + g_return_val_if_reached (NULL); + return NULL; + } +} + +static const char * +slave_category (NMPlatform *platform, int slave) +{ + int master = link_get_master (platform, slave); + + if (master <= 0) { + platform->error = NM_PLATFORM_ERROR_NOT_SLAVE; + return NULL; + } + + switch (link_get_type (platform, master)) { + case NM_LINK_TYPE_BRIDGE: + return "brport"; + default: + g_return_val_if_reached (NULL); + return NULL; + } +} + +static gboolean +master_set_option (NMPlatform *platform, int master, const char *option, const char *value) +{ + return link_set_option (master, master_category (platform, master), option, value); +} + +static char * +master_get_option (NMPlatform *platform, int master, const char *option) +{ + return link_get_option (master, master_category (platform, master), option); +} + +static gboolean +slave_set_option (NMPlatform *platform, int slave, const char *option, const char *value) +{ + return link_set_option (slave, slave_category (platform, slave), option, value); +} + +static char * +slave_get_option (NMPlatform *platform, int slave, const char *option) +{ + return link_get_option (slave, slave_category (platform, slave), option); +} + +static gboolean +infiniband_partition_add (NMPlatform *platform, int parent, int p_key) +{ + const char *parent_name; + char *path, *id; + gboolean success; + + parent_name = nm_platform_link_get_name (parent); + g_return_val_if_fail (parent_name != NULL, FALSE); + + path = g_strdup_printf ("/sys/class/net/%s/create_child", ASSERT_VALID_PATH_COMPONENT (parent_name)); + id = g_strdup_printf ("0x%04x", p_key); + success = nm_platform_sysctl_set (path, id); + g_free (id); + g_free (path); + + if (success) { + auto_g_free char *ifname = g_strdup_printf ("%s.%04x", parent_name, p_key); + auto_nl_object struct rtnl_link *rtnllink = _nm_rtnl_link_alloc (0, ifname); + + success = refresh_object (platform, (struct nl_object *) rtnllink, FALSE, NM_PLATFORM_REASON_INTERNAL); + } + + return success; +} + +static gboolean +veth_get_properties (NMPlatform *platform, int ifindex, NMPlatformVethProperties *props) +{ + const char *ifname; + auto_g_free struct ethtool_stats *stats = NULL; + int peer_ifindex_stat; + + ifname = nm_platform_link_get_name (ifindex); + if (!ifname) + return FALSE; + + peer_ifindex_stat = ethtool_get_stringset_index (ifname, ETH_SS_STATS, "peer_ifindex"); + if (peer_ifindex_stat == -1) { + debug ("%s: peer_ifindex ethtool stat does not exist?", ifname); + return FALSE; + } + + stats = g_malloc0 (sizeof (*stats) + (peer_ifindex_stat + 1) * sizeof (guint64)); + stats->cmd = ETHTOOL_GSTATS; + stats->n_stats = peer_ifindex_stat + 1; + if (!ethtool_get (ifname, stats)) + return FALSE; + + props->peer = stats->data[peer_ifindex_stat]; + return TRUE; +} + +static gboolean +tun_get_properties (NMPlatform *platform, int ifindex, NMPlatformTunProperties *props) +{ + const char *ifname; + char *path, *val; + gboolean success = TRUE; + + g_return_val_if_fail (props, FALSE); + + memset (props, 0, sizeof (*props)); + props->owner = -1; + props->group = -1; + + ifname = nm_platform_link_get_name (ifindex); + if (!ifname || !nm_utils_iface_valid_name (ifname)) + return FALSE; + ifname = ASSERT_VALID_PATH_COMPONENT (ifname); + + path = g_strdup_printf ("/sys/class/net/%s/owner", ifname); + val = nm_platform_sysctl_get (path); + g_free (path); + if (val) { + props->owner = nm_utils_ascii_str_to_int64 (val, 10, -1, G_MAXINT64, -1); + if (errno) + success = FALSE; + g_free (val); + } else + success = FALSE; + + path = g_strdup_printf ("/sys/class/net/%s/group", ifname); + val = nm_platform_sysctl_get (path); + g_free (path); + if (val) { + props->group = nm_utils_ascii_str_to_int64 (val, 10, -1, G_MAXINT64, -1); + if (errno) + success = FALSE; + g_free (val); + } else + success = FALSE; + + path = g_strdup_printf ("/sys/class/net/%s/tun_flags", ifname); + val = nm_platform_sysctl_get (path); + g_free (path); + if (val) { + gint64 flags; + + flags = nm_utils_ascii_str_to_int64 (val, 16, 0, G_MAXINT64, 0); + if (!errno) { +#ifndef IFF_MULTI_QUEUE + const int IFF_MULTI_QUEUE = 0x0100; +#endif + props->mode = ((flags & TUN_TYPE_MASK) == TUN_TUN_DEV) ? "tun" : "tap"; + props->no_pi = !!(flags & IFF_NO_PI); + props->vnet_hdr = !!(flags & IFF_VNET_HDR); + props->multi_queue = !!(flags & IFF_MULTI_QUEUE); + } else + success = FALSE; + g_free (val); + } else + success = FALSE; + + return success; +} + +static const struct nla_policy macvlan_info_policy[IFLA_MACVLAN_MAX + 1] = { + [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, +#ifdef MACVLAN_FLAG_NOPROMISC + [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 }, +#endif +}; + +static int +macvlan_info_data_parser (struct nlattr *info_data, gpointer parser_data) +{ + NMPlatformMacvlanProperties *props = parser_data; + struct nlattr *tb[IFLA_MACVLAN_MAX + 1]; + int err; + + err = nla_parse_nested (tb, IFLA_MACVLAN_MAX, info_data, + (struct nla_policy *) macvlan_info_policy); + if (err < 0) + return err; + + switch (nla_get_u32 (tb[IFLA_MACVLAN_MODE])) { + case MACVLAN_MODE_PRIVATE: + props->mode = "private"; + break; + case MACVLAN_MODE_VEPA: + props->mode = "vepa"; + break; + case MACVLAN_MODE_BRIDGE: + props->mode = "bridge"; + break; + case MACVLAN_MODE_PASSTHRU: + props->mode = "passthru"; + break; + default: + return -NLE_PARSE_ERR; + } + +#ifdef MACVLAN_FLAG_NOPROMISC + props->no_promisc = !!(nla_get_u16 (tb[IFLA_MACVLAN_FLAGS]) & MACVLAN_FLAG_NOPROMISC); +#else + props->no_promisc = FALSE; +#endif + + return 0; +} + +static gboolean +macvlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformMacvlanProperties *props) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + auto_nl_object struct rtnl_link *rtnllink = NULL; + int err; + + rtnllink = link_get (platform, ifindex); + if (!rtnllink) + return FALSE; + + props->parent_ifindex = rtnl_link_get_link (rtnllink); + + err = nm_rtnl_link_parse_info_data (priv->nlh, ifindex, + macvlan_info_data_parser, props); + if (err != 0) { + warning ("(%s) could not read properties: %s", + rtnl_link_get_name (rtnllink), nl_geterror (err)); + } + return (err == 0); +} + +/* The installed kernel headers might not have VXLAN stuff at all, or + * they might have the original properties, but not PORT, GROUP6, or LOCAL6. + * So until we depend on kernel >= 3.11, we just ignore the actual enum + * in if_link.h and define the values ourselves. + */ +#define IFLA_VXLAN_UNSPEC 0 +#define IFLA_VXLAN_ID 1 +#define IFLA_VXLAN_GROUP 2 +#define IFLA_VXLAN_LINK 3 +#define IFLA_VXLAN_LOCAL 4 +#define IFLA_VXLAN_TTL 5 +#define IFLA_VXLAN_TOS 6 +#define IFLA_VXLAN_LEARNING 7 +#define IFLA_VXLAN_AGEING 8 +#define IFLA_VXLAN_LIMIT 9 +#define IFLA_VXLAN_PORT_RANGE 10 +#define IFLA_VXLAN_PROXY 11 +#define IFLA_VXLAN_RSC 12 +#define IFLA_VXLAN_L2MISS 13 +#define IFLA_VXLAN_L3MISS 14 +#define IFLA_VXLAN_PORT 15 +#define IFLA_VXLAN_GROUP6 16 +#define IFLA_VXLAN_LOCAL6 17 +#undef IFLA_VXLAN_MAX +#define IFLA_VXLAN_MAX IFLA_VXLAN_LOCAL6 + +static const struct nla_policy vxlan_info_policy[IFLA_VXLAN_MAX + 1] = { + [IFLA_VXLAN_ID] = { .type = NLA_U32 }, + [IFLA_VXLAN_GROUP] = { .type = NLA_U32 }, + [IFLA_VXLAN_GROUP6] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct in6_addr) }, + [IFLA_VXLAN_LINK] = { .type = NLA_U32 }, + [IFLA_VXLAN_LOCAL] = { .type = NLA_U32 }, + [IFLA_VXLAN_LOCAL6] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct in6_addr) }, + [IFLA_VXLAN_TOS] = { .type = NLA_U8 }, + [IFLA_VXLAN_TTL] = { .type = NLA_U8 }, + [IFLA_VXLAN_LEARNING] = { .type = NLA_U8 }, + [IFLA_VXLAN_AGEING] = { .type = NLA_U32 }, + [IFLA_VXLAN_LIMIT] = { .type = NLA_U32 }, + [IFLA_VXLAN_PORT_RANGE] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct ifla_vxlan_port_range) }, + [IFLA_VXLAN_PROXY] = { .type = NLA_U8 }, + [IFLA_VXLAN_RSC] = { .type = NLA_U8 }, + [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 }, + [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 }, + [IFLA_VXLAN_PORT] = { .type = NLA_U16 }, +}; + +static int +vxlan_info_data_parser (struct nlattr *info_data, gpointer parser_data) +{ + NMPlatformVxlanProperties *props = parser_data; + struct nlattr *tb[IFLA_VXLAN_MAX + 1]; + struct ifla_vxlan_port_range *range; + int err; + + err = nla_parse_nested (tb, IFLA_VXLAN_MAX, info_data, + (struct nla_policy *) vxlan_info_policy); + if (err < 0) + return err; + + memset (props, 0, sizeof (*props)); + + props->parent_ifindex = tb[IFLA_VXLAN_LINK] ? nla_get_u32 (tb[IFLA_VXLAN_LINK]) : 0; + props->id = nla_get_u32 (tb[IFLA_VXLAN_ID]); + if (tb[IFLA_VXLAN_GROUP]) + props->group = nla_get_u32 (tb[IFLA_VXLAN_GROUP]); + if (tb[IFLA_VXLAN_LOCAL]) + props->local = nla_get_u32 (tb[IFLA_VXLAN_LOCAL]); + if (tb[IFLA_VXLAN_GROUP6]) + memcpy (&props->group6, nla_data (tb[IFLA_VXLAN_GROUP6]), sizeof (props->group6)); + if (tb[IFLA_VXLAN_LOCAL6]) + memcpy (&props->local6, nla_data (tb[IFLA_VXLAN_LOCAL6]), sizeof (props->local6)); + + props->ageing = nla_get_u32 (tb[IFLA_VXLAN_AGEING]); + props->limit = nla_get_u32 (tb[IFLA_VXLAN_LIMIT]); + props->tos = nla_get_u8 (tb[IFLA_VXLAN_TOS]); + props->ttl = nla_get_u8 (tb[IFLA_VXLAN_TTL]); + + props->dst_port = nla_get_u16 (tb[IFLA_VXLAN_PORT]); + range = nla_data (tb[IFLA_VXLAN_PORT_RANGE]); + props->src_port_min = range->low; + props->src_port_max = range->high; + + props->learning = !!nla_get_u8 (tb[IFLA_VXLAN_LEARNING]); + props->proxy = !!nla_get_u8 (tb[IFLA_VXLAN_PROXY]); + props->rsc = !!nla_get_u8 (tb[IFLA_VXLAN_RSC]); + props->l2miss = !!nla_get_u8 (tb[IFLA_VXLAN_L2MISS]); + props->l3miss = !!nla_get_u8 (tb[IFLA_VXLAN_L3MISS]); + + return 0; +} + +static gboolean +vxlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformVxlanProperties *props) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + int err; + + err = nm_rtnl_link_parse_info_data (priv->nlh, ifindex, + vxlan_info_data_parser, props); + if (err != 0) { + warning ("(%s) could not read properties: %s", + link_get_name (platform, ifindex), nl_geterror (err)); + } + return (err == 0); +} + +static const struct nla_policy gre_info_policy[IFLA_GRE_MAX + 1] = { + [IFLA_GRE_LINK] = { .type = NLA_U32 }, + [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, + [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, + [IFLA_GRE_IKEY] = { .type = NLA_U32 }, + [IFLA_GRE_OKEY] = { .type = NLA_U32 }, + [IFLA_GRE_LOCAL] = { .type = NLA_U32 }, + [IFLA_GRE_REMOTE] = { .type = NLA_U32 }, + [IFLA_GRE_TTL] = { .type = NLA_U8 }, + [IFLA_GRE_TOS] = { .type = NLA_U8 }, + [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 }, +}; + +static int +gre_info_data_parser (struct nlattr *info_data, gpointer parser_data) +{ + NMPlatformGreProperties *props = parser_data; + struct nlattr *tb[IFLA_GRE_MAX + 1]; + int err; + + err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, + (struct nla_policy *) gre_info_policy); + if (err < 0) + return err; + + props->parent_ifindex = tb[IFLA_GRE_LINK] ? nla_get_u32 (tb[IFLA_GRE_LINK]) : 0; + props->input_flags = nla_get_u16 (tb[IFLA_GRE_IFLAGS]); + props->output_flags = nla_get_u16 (tb[IFLA_GRE_OFLAGS]); + props->input_key = (props->input_flags & GRE_KEY) ? nla_get_u32 (tb[IFLA_GRE_IKEY]) : 0; + props->output_key = (props->output_flags & GRE_KEY) ? nla_get_u32 (tb[IFLA_GRE_OKEY]) : 0; + props->local = nla_get_u32 (tb[IFLA_GRE_LOCAL]); + props->remote = nla_get_u32 (tb[IFLA_GRE_REMOTE]); + props->tos = nla_get_u8 (tb[IFLA_GRE_TOS]); + props->ttl = nla_get_u8 (tb[IFLA_GRE_TTL]); + props->path_mtu_discovery = !!nla_get_u8 (tb[IFLA_GRE_PMTUDISC]); + + return 0; +} + +static gboolean +gre_get_properties (NMPlatform *platform, int ifindex, NMPlatformGreProperties *props) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + int err; + + err = nm_rtnl_link_parse_info_data (priv->nlh, ifindex, + gre_info_data_parser, props); + if (err != 0) { + warning ("(%s) could not read properties: %s", + link_get_name (platform, ifindex), nl_geterror (err)); + } + return (err == 0); +} + +static WifiData * +wifi_get_wifi_data (NMPlatform *platform, int ifindex) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + WifiData *wifi_data; + + wifi_data = g_hash_table_lookup (priv->wifi_data, GINT_TO_POINTER (ifindex)); + if (!wifi_data) { + NMLinkType type; + const char *ifname; + + type = link_get_type (platform, ifindex); + ifname = link_get_name (platform, ifindex); + + if (type == NM_LINK_TYPE_WIFI) + wifi_data = wifi_utils_init (ifname, ifindex, TRUE); + else if (type == NM_LINK_TYPE_OLPC_MESH) { + /* The kernel driver now uses nl80211, but we force use of WEXT because + * the cfg80211 interactions are not quite ready to support access to + * mesh control through nl80211 just yet. + */ +#if HAVE_WEXT + wifi_data = wifi_wext_init (ifname, ifindex, FALSE); +#endif + } + + if (wifi_data) + g_hash_table_insert (priv->wifi_data, GINT_TO_POINTER (ifindex), wifi_data); + } + + return wifi_data; +} + +static gboolean +wifi_get_capabilities (NMPlatform *platform, int ifindex, NMDeviceWifiCapabilities *caps) +{ + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (!wifi_data) + return FALSE; + + if (caps) + *caps = wifi_utils_get_caps (wifi_data); + return TRUE; +} + +static gboolean +wifi_get_bssid (NMPlatform *platform, int ifindex, struct ether_addr *bssid) +{ + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (!wifi_data) + return FALSE; + return wifi_utils_get_bssid (wifi_data, bssid); +} + +static GByteArray * +wifi_get_ssid (NMPlatform *platform, int ifindex) +{ + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (!wifi_data) + return NULL; + return wifi_utils_get_ssid (wifi_data); +} + +static guint32 +wifi_get_frequency (NMPlatform *platform, int ifindex) +{ + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (!wifi_data) + return 0; + return wifi_utils_get_freq (wifi_data); +} + +static gboolean +wifi_get_quality (NMPlatform *platform, int ifindex) +{ + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (!wifi_data) + return FALSE; + return wifi_utils_get_qual (wifi_data); +} + +static guint32 +wifi_get_rate (NMPlatform *platform, int ifindex) +{ + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (!wifi_data) + return FALSE; + return wifi_utils_get_rate (wifi_data); +} + +static NM80211Mode +wifi_get_mode (NMPlatform *platform, int ifindex) +{ + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (!wifi_data) + return NM_802_11_MODE_UNKNOWN; + + return wifi_utils_get_mode (wifi_data); +} + +static void +wifi_set_mode (NMPlatform *platform, int ifindex, NM80211Mode mode) +{ + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (wifi_data) + wifi_utils_set_mode (wifi_data, mode); +} + +static guint32 +wifi_find_frequency (NMPlatform *platform, int ifindex, const guint32 *freqs) +{ + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (!wifi_data) + return 0; + + return wifi_utils_find_freq (wifi_data, freqs); +} + +static void +wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean running) +{ + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (wifi_data) + wifi_utils_indicate_addressing_running (wifi_data, running); +} + + +static guint32 +mesh_get_channel (NMPlatform *platform, int ifindex) +{ + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (!wifi_data) + return 0; + + return wifi_utils_get_mesh_channel (wifi_data); +} + +static gboolean +mesh_set_channel (NMPlatform *platform, int ifindex, guint32 channel) +{ + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (!wifi_data) + return FALSE; + + return wifi_utils_set_mesh_channel (wifi_data, channel); +} + +static gboolean +mesh_set_ssid (NMPlatform *platform, int ifindex, const GByteArray *ssid) +{ + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (!wifi_data) + return FALSE; + + return wifi_utils_set_mesh_ssid (wifi_data, ssid); +} + +static gboolean +link_get_wake_on_lan (NMPlatform *platform, int ifindex) +{ + NMLinkType type = link_get_type (platform, ifindex); + + if (type == NM_LINK_TYPE_ETHERNET) { + struct ethtool_wolinfo wol; + + memset (&wol, 0, sizeof (wol)); + wol.cmd = ETHTOOL_GWOL; + if (!ethtool_get (link_get_name (platform, ifindex), &wol)) + return FALSE; + + return wol.wolopts != 0; + } else if (type == NM_LINK_TYPE_WIFI) { + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (!wifi_data) + return FALSE; + + return wifi_utils_get_wowlan (wifi_data); + } else + return FALSE; +} + +/******************************************************************/ + +static gboolean +_address_match (struct rtnl_addr *addr, int family, int ifindex) +{ + g_return_val_if_fail (addr, FALSE); + + return rtnl_addr_get_family (addr) == family && + rtnl_addr_get_ifindex (addr) == ifindex; +} + +static GArray * +ip4_address_get_all (NMPlatform *platform, int ifindex) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + GArray *addresses; + NMPlatformIP4Address address; + struct nl_object *object; + + addresses = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Address)); + + for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) { + if (_address_match ((struct rtnl_addr *) object, AF_INET, ifindex)) { + if (init_ip4_address (&address, (struct rtnl_addr *) object)) + g_array_append_val (addresses, address); + } + } + + return addresses; +} + +static GArray * +ip6_address_get_all (NMPlatform *platform, int ifindex) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + GArray *addresses; + NMPlatformIP6Address address; + struct nl_object *object; + + addresses = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP6Address)); + + for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) { + if (_address_match ((struct rtnl_addr *) object, AF_INET6, ifindex)) { + if (init_ip6_address (&address, (struct rtnl_addr *) object)) + g_array_append_val (addresses, address); + } + } + + return addresses; +} + +#define IPV4LL_NETWORK (htonl (0xA9FE0000L)) +#define IPV4LL_NETMASK (htonl (0xFFFF0000L)) + +static gboolean +ip4_is_link_local (const struct in_addr *src) +{ + return (src->s_addr & IPV4LL_NETMASK) == IPV4LL_NETWORK; +} + +static struct nl_object * +build_rtnl_addr (int family, + int ifindex, + gconstpointer addr, + gconstpointer peer_addr, + int plen, + guint32 lifetime, + guint32 preferred, + guint flags, + const char *label) +{ + auto_nl_addr struct rtnl_addr *rtnladdr = _nm_rtnl_addr_alloc (ifindex); + struct rtnl_addr *rtnladdr_copy; + int addrlen = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr); + auto_nl_addr struct nl_addr *nladdr = _nm_nl_addr_build (family, addr, addrlen); + int nle; + + /* IP address */ + nle = rtnl_addr_set_local (rtnladdr, nladdr); + if (nle) { + error ("build_rtnl_addr(): rtnl_addr_set_local failed with %s (%d)", nl_geterror (nle), nle); + return NULL; + } + + /* Tighten scope (IPv4 only) */ + if (family == AF_INET && ip4_is_link_local (addr)) + rtnl_addr_set_scope (rtnladdr, rtnl_str2scope ("link")); + + /* IPv4 Broadcast address */ + if (family == AF_INET) { + in_addr_t bcast; + auto_nl_addr struct nl_addr *bcaddr = NULL; + + bcast = *((in_addr_t *) addr) | ~nm_utils_ip4_prefix_to_netmask (plen); + bcaddr = _nm_nl_addr_build (family, &bcast, addrlen); + g_assert (bcaddr); + rtnl_addr_set_broadcast (rtnladdr, bcaddr); + } + + /* Peer/point-to-point address */ + if (peer_addr) { + auto_nl_addr struct nl_addr *nlpeer = _nm_nl_addr_build (family, peer_addr, addrlen); + + nle = rtnl_addr_set_peer (rtnladdr, nlpeer); + if (nle && nle != -NLE_AF_NOSUPPORT) { + /* IPv6 doesn't support peer addresses yet */ + error ("build_rtnl_addr(): rtnl_addr_set_peer failed with %s (%d)", nl_geterror (nle), nle); + return NULL; + } + } + + rtnl_addr_set_prefixlen (rtnladdr, plen); + if (lifetime) { + /* note that here we set the relative timestamps (ticking from *now*). + * Contrary to the rtnl_addr objects from our cache, which have absolute + * timestamps (see _rtnl_addr_hack_lifetimes_rel_to_abs()). + * + * This is correct, because we only use build_rtnl_addr() for + * add_object(), delete_object() and cache search (ip_address_exists). */ + rtnl_addr_set_valid_lifetime (rtnladdr, lifetime); + rtnl_addr_set_preferred_lifetime (rtnladdr, preferred); + } + if (flags) { + if ((flags & ~0xFF) && !check_support_kernel_extended_ifa_flags (nm_platform_get ())) { + /* Older kernels don't accept unknown netlink attributes. + * + * With commit libnl commit 5206c050504f8676a24854519b9c351470fb7cc6, libnl will only set + * the extended address flags attribute IFA_FLAGS when necessary (> 8 bit). But it's up to + * us not to shove those extended flags on to older kernels. + * + * Just silently clear them. The kernel should ignore those unknown flags anyway. */ + flags &= 0xFF; + } + rtnl_addr_set_flags (rtnladdr, flags); + } + if (label && *label) + rtnl_addr_set_label (rtnladdr, label); + + rtnladdr_copy = rtnladdr; + rtnladdr = NULL; + return (struct nl_object *) rtnladdr_copy; +} + +static gboolean +ip4_address_add (NMPlatform *platform, + int ifindex, + in_addr_t addr, + in_addr_t peer_addr, + int plen, + guint32 lifetime, + guint32 preferred, + const char *label) +{ + return add_object (platform, build_rtnl_addr (AF_INET, ifindex, &addr, + peer_addr ? &peer_addr : NULL, + plen, lifetime, preferred, 0, + label)); +} + +static gboolean +ip6_address_add (NMPlatform *platform, + int ifindex, + struct in6_addr addr, + struct in6_addr peer_addr, + int plen, + guint32 lifetime, + guint32 preferred, + guint flags) +{ + return add_object (platform, build_rtnl_addr (AF_INET6, ifindex, &addr, + IN6_IS_ADDR_UNSPECIFIED (&peer_addr) ? NULL : &peer_addr, + plen, lifetime, preferred, flags, + NULL)); +} + +static gboolean +ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen) +{ + return delete_object (platform, build_rtnl_addr (AF_INET, ifindex, &addr, NULL, plen, 0, 0, 0, NULL), TRUE); +} + +static gboolean +ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen) +{ + return delete_object (platform, build_rtnl_addr (AF_INET6, ifindex, &addr, NULL, plen, 0, 0, 0, NULL), TRUE); +} + +static gboolean +ip_address_exists (NMPlatform *platform, int family, int ifindex, gconstpointer addr, int plen) +{ + auto_nl_object struct nl_object *object = build_rtnl_addr (family, ifindex, addr, NULL, plen, 0, 0, 0, NULL); + auto_nl_object struct nl_object *cached_object = nl_cache_search (choose_cache (platform, object), object); + + return !!cached_object; +} + +static gboolean +ip4_address_exists (NMPlatform *platform, int ifindex, in_addr_t addr, int plen) +{ + return ip_address_exists (platform, AF_INET, ifindex, &addr, plen); +} + +static gboolean +ip6_address_exists (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen) +{ + return ip_address_exists (platform, AF_INET6, ifindex, &addr, plen); +} + +/******************************************************************/ + +static gboolean +_route_match (struct rtnl_route *rtnlroute, int family, int ifindex) +{ + struct rtnl_nexthop *nexthop; + + g_return_val_if_fail (rtnlroute, FALSE); + + if (rtnl_route_get_type (rtnlroute) != RTN_UNICAST || + rtnl_route_get_table (rtnlroute) != RT_TABLE_MAIN || + rtnl_route_get_protocol (rtnlroute) == RTPROT_KERNEL || + rtnl_route_get_family (rtnlroute) != family || + rtnl_route_get_nnexthops (rtnlroute) != 1) + return FALSE; + + nexthop = rtnl_route_nexthop_n (rtnlroute, 0); + return rtnl_route_nh_get_ifindex (nexthop) == ifindex; +} + +static GArray * +ip4_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + GArray *routes; + NMPlatformIP4Route route; + struct nl_object *object; + + routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route)); + + for (object = nl_cache_get_first (priv->route_cache); object; object = nl_cache_get_next (object)) { + if (_route_match ((struct rtnl_route *) object, AF_INET, ifindex)) { + if (init_ip4_route (&route, (struct rtnl_route *) object)) { + if (route.plen != 0 || include_default) + g_array_append_val (routes, route); + } + } + } + + return routes; +} + +static GArray * +ip6_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + GArray *routes; + NMPlatformIP6Route route; + struct nl_object *object; + + routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP6Route)); + + for (object = nl_cache_get_first (priv->route_cache); object; object = nl_cache_get_next (object)) { + if (_route_match ((struct rtnl_route *) object, AF_INET6, ifindex)) { + if (init_ip6_route (&route, (struct rtnl_route *) object)) { + if (route.plen != 0 || include_default) + g_array_append_val (routes, route); + } + } + } + + return routes; +} + +static void +clear_host_address (int family, const void *network, int plen, void *dst) +{ + g_return_if_fail (plen == (guint8)plen); + g_return_if_fail (network); + + switch (family) { + case AF_INET: + *((in_addr_t *) dst) = nm_utils_ip4_address_clear_host_address (*((in_addr_t *) network), plen); + break; + case AF_INET6: + nm_utils_ip6_address_clear_host_address ((struct in6_addr *) dst, (const struct in6_addr *) network, plen); + break; + default: + g_assert_not_reached (); + } +} + +static struct nl_object * +build_rtnl_route (int family, int ifindex, NMPlatformSource source, + gconstpointer network, int plen, gconstpointer gateway, + int metric, int mss) +{ + guint32 network_clean[4]; + struct rtnl_route *rtnlroute; + struct rtnl_nexthop *nexthop; + int addrlen = (family == AF_INET) ? sizeof (in_addr_t) : sizeof (struct in6_addr); + /* Workaround a libnl bug by using zero destination address length for default routes */ + auto_nl_addr struct nl_addr *dst = NULL; + auto_nl_addr struct nl_addr *gw = gateway ? _nm_nl_addr_build (family, gateway, addrlen) : NULL; + + /* There seem to be problems adding a route with non-zero host identifier. + * Adding IPv6 routes is simply ignored, without error message. + * In the IPv4 case, we got an error. Thus, we have to make sure, that + * the address is sane. */ + clear_host_address (family, network, plen, network_clean); + dst = _nm_nl_addr_build (family, network_clean, plen ? addrlen : 0); + nl_addr_set_prefixlen (dst, plen); + + rtnlroute = _nm_rtnl_route_alloc (); + rtnl_route_set_table (rtnlroute, RT_TABLE_MAIN); + rtnl_route_set_tos (rtnlroute, 0); + rtnl_route_set_dst (rtnlroute, dst); + rtnl_route_set_priority (rtnlroute, metric); + rtnl_route_set_family (rtnlroute, family); + rtnl_route_set_protocol (rtnlroute, source_to_rtprot (source)); + + nexthop = _nm_rtnl_route_nh_alloc (); + rtnl_route_nh_set_ifindex (nexthop, ifindex); + if (gw && !nl_addr_iszero (gw)) + rtnl_route_nh_set_gateway (nexthop, gw); + rtnl_route_add_nexthop (rtnlroute, nexthop); + + if (mss > 0) + rtnl_route_set_metric (rtnlroute, RTAX_ADVMSS, mss); + + return (struct nl_object *) rtnlroute; +} + +static gboolean +ip4_route_add (NMPlatform *platform, int ifindex, NMPlatformSource source, + in_addr_t network, int plen, in_addr_t gateway, + int metric, int mss) +{ + return add_object (platform, build_rtnl_route (AF_INET, ifindex, source, &network, plen, &gateway, metric, mss)); +} + +static gboolean +ip6_route_add (NMPlatform *platform, int ifindex, NMPlatformSource source, + struct in6_addr network, int plen, struct in6_addr gateway, + int metric, int mss) +{ + return add_object (platform, build_rtnl_route (AF_INET6, ifindex, source, &network, plen, &gateway, metric, mss)); +} + +static struct rtnl_route * +route_search_cache (struct nl_cache *cache, int family, int ifindex, const void *network, int plen, int metric) +{ + guint32 network_clean[4], dst_clean[4]; + struct nl_object *object; + + clear_host_address (family, network, plen, network_clean); + + for (object = nl_cache_get_first (cache); object; object = nl_cache_get_next (object)) { + struct nl_addr *dst; + struct rtnl_route *rtnlroute = (struct rtnl_route *) object; + + if (!_route_match (rtnlroute, family, ifindex)) + continue; + + if (metric && metric != rtnl_route_get_priority (rtnlroute)) + continue; + + dst = rtnl_route_get_dst (rtnlroute); + if ( !dst + || nl_addr_get_family (dst) != family + || nl_addr_get_prefixlen (dst) != plen) + continue; + + clear_host_address (family, nl_addr_get_binary_addr (dst), plen, dst_clean); + if (memcmp (dst_clean, network_clean, + family == AF_INET ? sizeof (guint32) : sizeof (struct in6_addr)) != 0) + continue; + + rtnl_route_get (rtnlroute); + return rtnlroute; + } + return NULL; +} + +static gboolean +refresh_route (NMPlatform *platform, int family, int ifindex, const void *network, int plen, int metric) +{ + struct nl_cache *cache; + auto_nl_object struct rtnl_route *cached_object = NULL; + + cache = choose_cache_by_type (platform, family == AF_INET ? OBJECT_TYPE_IP4_ROUTE : OBJECT_TYPE_IP6_ROUTE); + cached_object = route_search_cache (cache, family, ifindex, network, plen, metric); + + if (cached_object) + return refresh_object (platform, (struct nl_object *) cached_object, TRUE, NM_PLATFORM_REASON_INTERNAL); + return TRUE; +} + +static gboolean +ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen, int metric) +{ + in_addr_t gateway = 0; + struct rtnl_route *cached_object; + struct nl_object *route = build_rtnl_route (AF_INET, ifindex, NM_PLATFORM_SOURCE_UNKNOWN, &network, plen, &gateway, metric, 0); + uint8_t scope = RT_SCOPE_NOWHERE; + struct nl_cache *cache; + + g_return_val_if_fail (route, FALSE); + + cache = choose_cache_by_type (platform, OBJECT_TYPE_IP4_ROUTE); + + /* when deleting an IPv4 route, several fields of the provided route must match. + * Lookup in the cache so that we hopefully get the right values. */ + cached_object = (struct rtnl_route *) nl_cache_search (cache, route); + if (!cached_object) + cached_object = route_search_cache (cache, AF_INET, ifindex, &network, plen, metric); + + if (!_nl_has_capability (1 /* NL_CAPABILITY_ROUTE_BUILD_MSG_SET_SCOPE */)) { + /* When searching for a matching IPv4 route to delete, the kernel + * searches for a matching scope, unless the RTM_DELROUTE message + * specifies RT_SCOPE_NOWHERE (see fib_table_delete()). + * + * However, if we set the scope of @rtnlroute to RT_SCOPE_NOWHERE (or + * leave it unset), rtnl_route_build_msg() will reset the scope to + * rtnl_route_guess_scope() -- which probably guesses wrong. + * + * As a workaround, we look at the cached route and use that scope. + * + * Newer versions of libnl, no longer reset the scope if explicitly set to RT_SCOPE_NOWHERE. + * So, this workaround is only needed unless we have NL_CAPABILITY_ROUTE_BUILD_MSG_SET_SCOPE. + **/ + + if (cached_object) + scope = rtnl_route_get_scope (cached_object); + + if (scope == RT_SCOPE_NOWHERE) { + /* If we would set the scope to RT_SCOPE_NOWHERE, libnl would guess the scope. + * But probably it will guess 'link' because we set the next hop of the route + * to zero (0.0.0.0). A better guess is 'global'. */ + scope = RT_SCOPE_UNIVERSE; + } + } + rtnl_route_set_scope ((struct rtnl_route *) route, scope); + + if (cached_object) + rtnl_route_set_tos ((struct rtnl_route *) route, rtnl_route_get_tos (cached_object)); + + /* The following fields are also relevant when comparing the route, but the default values + * are already as we want them: + * + * type: RTN_UNICAST (setting to zero would ignore the type, but we only want to delete RTN_UNICAST) + * pref_src: NULL + */ + + rtnl_route_put (cached_object); + return delete_object (platform, route, FALSE) && refresh_route (platform, AF_INET, ifindex, &network, plen, metric); +} + +static gboolean +ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, int metric) +{ + struct in6_addr gateway = IN6ADDR_ANY_INIT; + + return delete_object (platform, build_rtnl_route (AF_INET6, ifindex, NM_PLATFORM_SOURCE_UNKNOWN ,&network, plen, &gateway, metric, 0), FALSE) && + refresh_route (platform, AF_INET6, ifindex, &network, plen, metric); +} + +static gboolean +ip_route_exists (NMPlatform *platform, int family, int ifindex, gpointer network, int plen, int metric) +{ + auto_nl_object struct nl_object *object = build_rtnl_route (family, ifindex, + NM_PLATFORM_SOURCE_UNKNOWN, + network, plen, NULL, metric, 0); + struct nl_cache *cache = choose_cache (platform, object); + auto_nl_object struct nl_object *cached_object = nl_cache_search (cache, object); + + if (!cached_object) + cached_object = (struct nl_object *) route_search_cache (cache, family, ifindex, network, plen, metric); + return !!cached_object; +} + +static gboolean +ip4_route_exists (NMPlatform *platform, int ifindex, in_addr_t network, int plen, int metric) +{ + return ip_route_exists (platform, AF_INET, ifindex, &network, plen, metric); +} + +static gboolean +ip6_route_exists (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, int metric) +{ + return ip_route_exists (platform, AF_INET6, ifindex, &network, plen, metric); +} + +/******************************************************************/ + +#define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI)) +#define ERROR_CONDITIONS ((GIOCondition) (G_IO_ERR | G_IO_NVAL)) +#define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP)) + +static int +verify_source (struct nl_msg *msg, gpointer user_data) +{ + struct ucred *creds = nlmsg_get_creds (msg); + + if (!creds || creds->pid || creds->uid || creds->gid) { + if (creds) + warning ("netlink: received non-kernel message (pid %d uid %d gid %d)", + creds->pid, creds->uid, creds->gid); + else + warning ("netlink: received message without credentials"); + return NL_STOP; + } + + return NL_OK; +} + +static gboolean +event_handler (GIOChannel *channel, + GIOCondition io_condition, + gpointer user_data) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (user_data); + int nle; + + nle = nl_recvmsgs_default (priv->nlh_event); + if (nle < 0) + switch (nle) { + case -NLE_DUMP_INTR: + /* this most likely happens due to our request (RTM_GETADDR, AF_INET6, NLM_F_DUMP) + * to detect support for support_kernel_extended_ifa_flags. This is not critical + * and can happen easily. */ + debug ("Uncritical failure to retrieve incoming events: %s (%d)", nl_geterror (nle), nle); + break; + default: + error ("Failed to retrieve incoming events: %s (%d)", nl_geterror (nle), nle); + break; + } + return TRUE; +} + +static struct nl_sock * +setup_socket (gboolean event, gpointer user_data) +{ + struct nl_sock *sock; + int nle; + + sock = nl_socket_alloc (); + g_return_val_if_fail (sock, NULL); + + /* Only ever accept messages from kernel */ + nle = nl_socket_modify_cb (sock, NL_CB_MSG_IN, NL_CB_CUSTOM, verify_source, user_data); + g_assert (!nle); + + /* Dispatch event messages (event socket only) */ + if (event) { + nl_socket_modify_cb (sock, NL_CB_VALID, NL_CB_CUSTOM, event_notification, user_data); + nl_socket_disable_seq_check (sock); + } + + nle = nl_connect (sock, NETLINK_ROUTE); + g_assert (!nle); + nle = nl_socket_set_passcred (sock, 1); + g_assert (!nle); + + return sock; +} + +/******************************************************************/ + +static void +udev_device_added (NMPlatform *platform, + GUdevDevice *udev_device) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + auto_nl_object struct rtnl_link *rtnllink = NULL; + const char *ifname; + int ifindex; + gboolean was_announceable = FALSE; + + ifname = g_udev_device_get_name (udev_device); + if (!ifname) { + debug ("udev-add: failed to get device's interface"); + return; + } + + if (g_udev_device_get_property (udev_device, "IFINDEX")) + ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX"); + else { + warning ("(%s): udev-add: failed to get device's ifindex", ifname); + return; + } + if (ifindex <= 0) { + warning ("(%s): udev-add: retrieved invalid IFINDEX=%d", ifname, ifindex); + return; + } + + if (!g_udev_device_get_sysfs_path (udev_device)) { + debug ("(%s): udev-add: couldn't determine device path; ignoring...", ifname); + return; + } + + rtnllink = rtnl_link_get (priv->link_cache, ifindex); + if (rtnllink) + was_announceable = link_is_announceable (platform, rtnllink); + + g_hash_table_insert (priv->udev_devices, GINT_TO_POINTER (ifindex), + g_object_ref (udev_device)); + + /* Announce devices only if they also have been discovered via Netlink. */ + if (rtnllink && link_is_announceable (platform, rtnllink)) + announce_object (platform, (struct nl_object *) rtnllink, was_announceable ? NM_PLATFORM_SIGNAL_CHANGED : NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_EXTERNAL); +} + +static void +udev_device_removed (NMPlatform *platform, + GUdevDevice *udev_device) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + auto_nl_object struct rtnl_link *rtnllink = NULL; + int ifindex = 0; + gboolean was_announceable = FALSE; + + if (g_udev_device_get_property (udev_device, "IFINDEX")) + ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX"); + else { + GHashTableIter iter; + gpointer key, value; + + /* This should not happen, but just to be sure. + * If we can't get IFINDEX, go through the devices and + * compare the pointers. + */ + g_hash_table_iter_init (&iter, priv->udev_devices); + while (g_hash_table_iter_next (&iter, &key, &value)) { + if ((GUdevDevice *)value == udev_device) { + ifindex = GPOINTER_TO_INT (key); + break; + } + } + } + + debug ("udev-remove: IFINDEX=%d", ifindex); + if (ifindex <= 0) + return; + + rtnllink = rtnl_link_get (priv->link_cache, ifindex); + if (rtnllink) + was_announceable = link_is_announceable (platform, rtnllink); + + g_hash_table_remove (priv->udev_devices, GINT_TO_POINTER (ifindex)); + + /* Announce device removal if it is no longer announceable. */ + if (was_announceable && !link_is_announceable (platform, rtnllink)) + announce_object (platform, (struct nl_object *) rtnllink, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_EXTERNAL); +} + +static void +handle_udev_event (GUdevClient *client, + const char *action, + GUdevDevice *udev_device, + gpointer user_data) +{ + NMPlatform *platform = NM_PLATFORM (user_data); + const char *subsys; + const char *ifindex; + guint64 seqnum; + + g_return_if_fail (action != NULL); + + /* A bit paranoid */ + subsys = g_udev_device_get_subsystem (udev_device); + g_return_if_fail (!g_strcmp0 (subsys, "net")); + + ifindex = g_udev_device_get_property (udev_device, "IFINDEX"); + seqnum = g_udev_device_get_seqnum (udev_device); + debug ("UDEV event: action '%s' subsys '%s' device '%s' (%s); seqnum=%" G_GUINT64_FORMAT, + action, subsys, g_udev_device_get_name (udev_device), + ifindex ? ifindex : "unknown", seqnum); + + if (!strcmp (action, "add") || !strcmp (action, "move")) + udev_device_added (platform, udev_device); + if (!strcmp (action, "remove")) + udev_device_removed (platform, udev_device); +} + +/******************************************************************/ + +static void +nm_linux_platform_init (NMLinuxPlatform *platform) +{ +} + +static gboolean +setup (NMPlatform *platform) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + const char *udev_subsys[] = { "net", NULL }; + GUdevEnumerator *enumerator; + GList *devices, *iter; + int channel_flags; + gboolean status; + int nle; + struct nl_object *object; + + /* Initialize netlink socket for requests */ + priv->nlh = setup_socket (FALSE, platform); + g_assert (priv->nlh); + debug ("Netlink socket for requests established: %d", nl_socket_get_local_port (priv->nlh)); + + /* Initialize netlink socket for events */ + priv->nlh_event = setup_socket (TRUE, platform); + g_assert (priv->nlh_event); + /* The default buffer size wasn't enough for the testsuites. It might just + * as well happen with NetworkManager itself. For now let's hope 128KB is + * good enough. + */ + nle = nl_socket_set_buffer_size (priv->nlh_event, 131072, 0); + g_assert (!nle); + nle = nl_socket_add_memberships (priv->nlh_event, + RTNLGRP_LINK, + RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, + RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, + 0); + g_assert (!nle); + debug ("Netlink socket for events established: %d", nl_socket_get_local_port (priv->nlh_event)); + + priv->event_channel = g_io_channel_unix_new (nl_socket_get_fd (priv->nlh_event)); + g_io_channel_set_encoding (priv->event_channel, NULL, NULL); + g_io_channel_set_close_on_unref (priv->event_channel, TRUE); + + channel_flags = g_io_channel_get_flags (priv->event_channel); + status = g_io_channel_set_flags (priv->event_channel, + channel_flags | G_IO_FLAG_NONBLOCK, NULL); + g_assert (status); + priv->event_id = g_io_add_watch (priv->event_channel, + (EVENT_CONDITIONS | ERROR_CONDITIONS | DISCONNECT_CONDITIONS), + event_handler, platform); + + /* Allocate netlink caches */ + rtnl_link_alloc_cache (priv->nlh, AF_UNSPEC, &priv->link_cache); + rtnl_addr_alloc_cache (priv->nlh, &priv->address_cache); + rtnl_route_alloc_cache (priv->nlh, AF_UNSPEC, 0, &priv->route_cache); + g_assert (priv->link_cache && priv->address_cache && priv->route_cache); + + for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) + _rtnl_addr_hack_lifetimes_rel_to_abs ((struct rtnl_addr *) object); + + /* Set up udev monitoring */ + priv->udev_client = g_udev_client_new (udev_subsys); + g_signal_connect (priv->udev_client, "uevent", G_CALLBACK (handle_udev_event), platform); + priv->udev_devices = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref); + + /* And read initial device list */ + enumerator = g_udev_enumerator_new (priv->udev_client); + g_udev_enumerator_add_match_subsystem (enumerator, "net"); + g_udev_enumerator_add_match_is_initialized (enumerator); + + devices = g_udev_enumerator_execute (enumerator); + for (iter = devices; iter; iter = g_list_next (iter)) { + udev_device_added (platform, G_UDEV_DEVICE (iter->data)); + g_object_unref (G_UDEV_DEVICE (iter->data)); + } + g_list_free (devices); + g_object_unref (enumerator); + + /* request all IPv6 addresses (hopeing that there is at least one), to check for + * the IFA_FLAGS attribute. */ + nle = nl_rtgen_request (priv->nlh_event, RTM_GETADDR, AF_INET6, NLM_F_DUMP); + if (nle < 0) + nm_log_warn (LOGD_PLATFORM, "Netlink error: requesting RTM_GETADDR failed with %s", nl_geterror (nle)); + + priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit); + + return TRUE; +} + +static void +nm_linux_platform_finalize (GObject *object) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (object); + + /* Free netlink resources */ + g_source_remove (priv->event_id); + g_io_channel_unref (priv->event_channel); + nl_socket_free (priv->nlh); + nl_socket_free (priv->nlh_event); + nl_cache_free (priv->link_cache); + nl_cache_free (priv->address_cache); + nl_cache_free (priv->route_cache); + + g_object_unref (priv->udev_client); + g_hash_table_unref (priv->udev_devices); + g_hash_table_unref (priv->wifi_data); + + G_OBJECT_CLASS (nm_linux_platform_parent_class)->finalize (object); +} + +#define OVERRIDE(function) platform_class->function = function + +static void +nm_linux_platform_class_init (NMLinuxPlatformClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMPlatformClass *platform_class = NM_PLATFORM_CLASS (klass); + + g_type_class_add_private (klass, sizeof (NMLinuxPlatformPrivate)); + + /* virtual methods */ + object_class->finalize = nm_linux_platform_finalize; + + platform_class->setup = setup; + + platform_class->sysctl_set = sysctl_set; + platform_class->sysctl_get = sysctl_get; + + platform_class->link_get = _nm_platform_link_get; + platform_class->link_get_all = link_get_all; + platform_class->link_add = link_add; + platform_class->link_delete = link_delete; + platform_class->link_get_ifindex = link_get_ifindex; + platform_class->link_get_name = link_get_name; + platform_class->link_get_type = link_get_type; + platform_class->link_get_type_name = link_get_type_name; + + platform_class->link_refresh = link_refresh; + + platform_class->link_set_up = link_set_up; + platform_class->link_set_down = link_set_down; + platform_class->link_set_arp = link_set_arp; + platform_class->link_set_noarp = link_set_noarp; + platform_class->link_is_up = link_is_up; + platform_class->link_is_connected = link_is_connected; + platform_class->link_uses_arp = link_uses_arp; + + platform_class->link_get_address = link_get_address; + platform_class->link_set_address = link_set_address; + platform_class->link_get_mtu = link_get_mtu; + platform_class->link_set_mtu = link_set_mtu; + + platform_class->link_get_physical_port_id = link_get_physical_port_id; + platform_class->link_get_wake_on_lan = link_get_wake_on_lan; + + platform_class->link_supports_carrier_detect = link_supports_carrier_detect; + platform_class->link_supports_vlans = link_supports_vlans; + + platform_class->link_enslave = link_enslave; + platform_class->link_release = link_release; + platform_class->link_get_master = link_get_master; + platform_class->master_set_option = master_set_option; + platform_class->master_get_option = master_get_option; + platform_class->slave_set_option = slave_set_option; + platform_class->slave_get_option = slave_get_option; + + platform_class->vlan_add = vlan_add; + platform_class->vlan_get_info = vlan_get_info; + platform_class->vlan_set_ingress_map = vlan_set_ingress_map; + platform_class->vlan_set_egress_map = vlan_set_egress_map; + + platform_class->infiniband_partition_add = infiniband_partition_add; + + platform_class->veth_get_properties = veth_get_properties; + platform_class->tun_get_properties = tun_get_properties; + platform_class->macvlan_get_properties = macvlan_get_properties; + platform_class->vxlan_get_properties = vxlan_get_properties; + platform_class->gre_get_properties = gre_get_properties; + + platform_class->wifi_get_capabilities = wifi_get_capabilities; + platform_class->wifi_get_bssid = wifi_get_bssid; + platform_class->wifi_get_ssid = wifi_get_ssid; + platform_class->wifi_get_frequency = wifi_get_frequency; + platform_class->wifi_get_quality = wifi_get_quality; + platform_class->wifi_get_rate = wifi_get_rate; + platform_class->wifi_get_mode = wifi_get_mode; + platform_class->wifi_set_mode = wifi_set_mode; + platform_class->wifi_find_frequency = wifi_find_frequency; + platform_class->wifi_indicate_addressing_running = wifi_indicate_addressing_running; + + platform_class->mesh_get_channel = mesh_get_channel; + platform_class->mesh_set_channel = mesh_set_channel; + platform_class->mesh_set_ssid = mesh_set_ssid; + + platform_class->ip4_address_get_all = ip4_address_get_all; + platform_class->ip6_address_get_all = ip6_address_get_all; + platform_class->ip4_address_add = ip4_address_add; + platform_class->ip6_address_add = ip6_address_add; + platform_class->ip4_address_delete = ip4_address_delete; + platform_class->ip6_address_delete = ip6_address_delete; + platform_class->ip4_address_exists = ip4_address_exists; + platform_class->ip6_address_exists = ip6_address_exists; + + platform_class->ip4_route_get_all = ip4_route_get_all; + platform_class->ip6_route_get_all = ip6_route_get_all; + platform_class->ip4_route_add = ip4_route_add; + platform_class->ip6_route_add = ip6_route_add; + platform_class->ip4_route_delete = ip4_route_delete; + platform_class->ip6_route_delete = ip6_route_delete; + platform_class->ip4_route_exists = ip4_route_exists; + platform_class->ip6_route_exists = ip6_route_exists; + + platform_class->check_support_kernel_extended_ifa_flags = check_support_kernel_extended_ifa_flags; +} diff --git a/src/platform/nm-linux-platform.h b/src/platform/nm-linux-platform.h new file mode 100644 index 00000000..53ea75e6 --- /dev/null +++ b/src/platform/nm-linux-platform.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-linux-platform.h - Linux kernel & udev network configuration layer + * + * 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, 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) 2012 Red Hat, Inc. + */ + +#ifndef NM_LINUX_PLATFORM_H +#define NM_LINUX_PLATFORM_H + +#include "nm-platform.h" + +#define NM_TYPE_LINUX_PLATFORM (nm_linux_platform_get_type ()) +#define NM_LINUX_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_LINUX_PLATFORM, NMLinuxPlatform)) +#define NM_LINUX_PLATFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformClass)) +#define NM_IS_LINUX_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_LINUX_PLATFORM)) +#define NM_IS_LINUX_PLATFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_LINUX_PLATFORM)) +#define NM_LINUX_PLATFORM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformClass)) + +/******************************************************************/ + +typedef struct { + NMPlatform parent; +} NMLinuxPlatform; + +typedef struct { + NMPlatformClass parent; +} NMLinuxPlatformClass; + +/******************************************************************/ + +GType nm_linux_platform_get_type (void); + +void nm_linux_platform_setup (void); + +#endif /* NM_LINUX_PLATFORM_H */ diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c new file mode 100644 index 00000000..542b0faa --- /dev/null +++ b/src/platform/nm-platform.c @@ -0,0 +1,2618 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-platform.c - Handle runtime kernel networking configuration + * + * 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, 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) 2012 Red Hat, Inc. + */ + +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include <netlink/route/addr.h> + +#include "NetworkManagerUtils.h" +#include "nm-utils.h" +#include "nm-platform.h" +#include "NetworkManagerUtils.h" +#include "nm-logging.h" +#include "nm-enum-types.h" + +#define debug(...) nm_log_dbg (LOGD_PLATFORM, __VA_ARGS__) + +#define NM_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_PLATFORM, NMPlatformPrivate)) + +G_DEFINE_TYPE (NMPlatform, nm_platform, G_TYPE_OBJECT) + +/* NMPlatform signals */ +enum { + SIGNAL_LINK_CHANGED, + SIGNAL_IP4_ADDRESS_CHANGED, + SIGNAL_IP6_ADDRESS_CHANGED, + SIGNAL_IP4_ROUTE_CHANGED, + SIGNAL_IP6_ROUTE_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +/******************************************************************/ + +/* Singleton NMPlatform subclass instance and cached class object */ +static NMPlatform *platform = NULL; +static NMPlatformClass *klass = NULL; + +/** + * nm_platform_setup: + * @type: The #GType for a subclass of #NMPlatform + * + * Do not use this function directly, it is intended to be called by + * NMPlatform subclasses. For the linux platform initialization use + * nm_linux_platform_setup() instead. + * + * Failing to set up #NMPlatform singleton results in a fatal error, + * as well as trying to initialize it multiple times without freeing + * it. + * + * NetworkManager will typically use only one platform object during + * its run. Test programs might want to switch platform implementations, + * though. This is done with a combination of nm_platform_free() and + * nm_*_platform_setup(). + */ +void +nm_platform_setup (GType type) +{ + gboolean status; + + g_assert (platform == NULL); + + platform = g_object_new (type, NULL); + g_assert (NM_IS_PLATFORM (platform)); + + klass = NM_PLATFORM_GET_CLASS (platform); + g_assert (klass->setup); + + status = klass->setup (platform); + g_assert (status); +} + +/** + * nm_platform_free: + * + * Free #NMPlatform singleton created by nm_*_platform_setup(). + */ +void +nm_platform_free (void) +{ + g_assert (platform); + + g_object_unref (platform); + platform = NULL; +} + +/** + * nm_platform_get: + * + * Retrieve #NMPlatform singleton. Use this whenever you want to connect to + * #NMPlatform signals. It is an error to call it before nm_*_platform_setup() + * or after nm_platform_free(). + * + * Returns: (transfer none): The #NMPlatform singleton reference. + */ +NMPlatform * +nm_platform_get (void) +{ + g_assert (platform); + + return platform; +} + +/******************************************************************/ + +/** + * nm_platform_set_error: + * @error: The error code + * + * Convenience function to falsify platform->error. It can be used for example + * by functions that want to save the error, execute some operations and + * restore it. + */ +void nm_platform_set_error (NMPlatformError error) +{ + platform->error = error; +} + +/** + * nm_platform_get_error: + * + * Convenience function to quickly retrieve the error code of the last + * operation. + * + * Returns: Integer error code. + */ +NMPlatformError +nm_platform_get_error (void) +{ + g_assert (platform); + + return platform->error; +} + +/** + * nm_platform_get_error_message: + * + * Returns: Static human-readable string for the error. Don't free. + */ +const char * +nm_platform_get_error_msg (void) +{ + g_assert (platform); + + switch (platform->error) { + case NM_PLATFORM_ERROR_NONE: + return "unknown error"; + case NM_PLATFORM_ERROR_NOT_FOUND: + return "object not found"; + case NM_PLATFORM_ERROR_EXISTS: + return "object already exists"; + case NM_PLATFORM_ERROR_WRONG_TYPE: + return "object is wrong type"; + case NM_PLATFORM_ERROR_NOT_SLAVE: + return "link not a slave"; + case NM_PLATFORM_ERROR_NO_FIRMWARE: + return "firmware not found"; + default: + return "invalid error number"; + } +} + +static void +reset_error (void) +{ + g_assert (platform); + platform->error = NM_PLATFORM_ERROR_NONE; +} + +#define IFA_F_MANAGETEMPADDR_STR "mngtmpaddr" +#define IFA_F_NOPREFIXROUTE_STR "noprefixroute" +gboolean +nm_platform_check_support_libnl_extended_ifa_flags () +{ + static int supported = -1; + + /* support for extended ifa-flags was added together + * with the IFA_F_MANAGETEMPADDR flag. So, check if libnl + * is able to parse this flag. */ + if (supported == -1) + supported = rtnl_addr_str2flags (IFA_F_MANAGETEMPADDR_STR) == IFA_F_MANAGETEMPADDR; + + return supported; +} + +gboolean +nm_platform_check_support_kernel_extended_ifa_flags () +{ + g_return_val_if_fail (NM_IS_PLATFORM (platform), FALSE); + + if (!klass->check_support_kernel_extended_ifa_flags) + return FALSE; + + return klass->check_support_kernel_extended_ifa_flags (platform); +} + +/******************************************************************/ + +/** + * nm_platform_sysctl_set: + * @path: Absolute option path + * @value: Value to write + * + * This function is intended to be used for writing values to sysctl-style + * virtual runtime configuration files. This includes not only /proc/sys + * but also for example /sys/class. + * + * Returns: %TRUE on success. + */ +gboolean +nm_platform_sysctl_set (const char *path, const char *value) +{ + reset_error (); + + g_return_val_if_fail (path, FALSE); + g_return_val_if_fail (value, FALSE); + g_return_val_if_fail (klass->sysctl_set, FALSE); + + return klass->sysctl_set (platform, path, value); +} + +/** + * nm_platform_sysctl_get: + * @path: Absolute path to sysctl + * + * Returns: (transfer full): Contents of the virtual sysctl file. + */ +char * +nm_platform_sysctl_get (const char *path) +{ + reset_error (); + + g_return_val_if_fail (path, NULL); + g_return_val_if_fail (klass->sysctl_get, NULL); + + return klass->sysctl_get (platform, path); +} + +/** + * nm_platform_sysctl_get_int32: + * @path: Absolute path to sysctl + * @fallback: default value, if the content of path could not be read + * as decimal integer. + * + * Returns: contents of the sysctl file parsed as s32 integer, or + * @fallback on error. On error, %errno will be set to a non-zero + * value, on success %errno will be set to zero. + */ +gint32 +nm_platform_sysctl_get_int32 (const char *path, gint32 fallback) +{ + return nm_platform_sysctl_get_int_checked (path, 10, G_MININT32, G_MAXINT32, fallback); +} + +/** + * nm_platform_sysctl_get_int_checked: + * @path: Absolute path to sysctl + * @base: base of numeric conversion + * @min: minimal value that is still valid + * @max: maximal value that is still valid + * @fallback: default value, if the content of path could not be read + * as valid integer. + * + * Returns: contents of the sysctl file parsed as s64 integer, or + * @fallback on error. On error, %errno will be set to a non-zero + * value. On success, %errno will be set to zero. The returned value + * will always be in the range between @min and @max + * (inclusive) or @fallback. + */ +gint64 +nm_platform_sysctl_get_int_checked (const char *path, guint base, gint64 min, gint64 max, gint64 fallback) +{ + char *value = NULL; + gint32 ret; + + g_return_val_if_fail (path, fallback); + + if (path) + value = nm_platform_sysctl_get (path); + + if (!value) { + errno = EINVAL; + return fallback; + } + + ret = nm_utils_ascii_str_to_int64 (value, base, min, max, fallback); + g_free (value); + return ret; +} + +/******************************************************************/ + +/** + * nm_platform_query_devices: + * + * Emit #NMPlatform:link-changed ADDED signals for all currently-known links. + * Should only be called at startup. + */ +void +nm_platform_query_devices (void) +{ + GArray *links_array; + NMPlatformLink *links; + int i; + + links_array = nm_platform_link_get_all (); + links = (NMPlatformLink *) links_array->data; + for (i = 0; i < links_array->len; i++) { + g_signal_emit (platform, signals[SIGNAL_LINK_CHANGED], 0, + links[i].ifindex, &links[i], NM_PLATFORM_SIGNAL_ADDED, + NM_PLATFORM_REASON_INTERNAL); + } + g_array_unref (links_array); +} + +/** + * nm_platform_link_get_all: + * + * Retrieve a snapshot of configuration for all links at once. The result is + * owned by the caller and should be freed with g_array_unref(). + */ +GArray * +nm_platform_link_get_all (void) +{ + GArray *links, *result; + guint i, j, nresult; + GHashTable *unseen; + NMPlatformLink *item; + + reset_error (); + + g_return_val_if_fail (klass->link_get_all, NULL); + + links = klass->link_get_all (platform); + + if (!links || links->len == 0) + return links; + + unseen = g_hash_table_new (g_direct_hash, g_direct_equal); + for (i = 0; i < links->len; i++) { + item = &g_array_index (links, NMPlatformLink, i); + + if (item->ifindex <= 0 || g_hash_table_contains (unseen, GINT_TO_POINTER (item->ifindex))) { + g_warn_if_reached (); + item->ifindex = 0; + continue; + } + + g_hash_table_insert (unseen, GINT_TO_POINTER (item->ifindex), NULL); + } + +#ifndef G_DISABLE_ASSERT + /* Ensure that link_get_all returns a consistent and valid result. */ + for (i = 0; i < links->len; i++) { + item = &g_array_index (links, NMPlatformLink, i); + + if (!item->ifindex) + continue; + if (item->master != 0) { + g_warn_if_fail (item->master > 0); + g_warn_if_fail (item->master != item->ifindex); + g_warn_if_fail (g_hash_table_contains (unseen, GINT_TO_POINTER (item->master))); + } + if (item->parent != 0) { + g_warn_if_fail (item->parent > 0); + g_warn_if_fail (item->parent != item->ifindex); + g_warn_if_fail (g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent))); + } + } +#endif + + /* Re-order the links list such that children/slaves come after all ancestors */ + nresult = g_hash_table_size (unseen); + result = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformLink), nresult); + g_array_set_size (result, nresult); + + j = 0; + do { + gboolean found_something = FALSE; + guint first_idx = G_MAXUINT; + + for (i = 0; i < links->len; i++) { + item = &g_array_index (links, NMPlatformLink, i); + + if (!item->ifindex) + continue; + + if (first_idx == G_MAXUINT) + first_idx = i; + + g_assert (g_hash_table_contains (unseen, GINT_TO_POINTER (item->ifindex))); + + if (item->master > 0 && g_hash_table_contains (unseen, GINT_TO_POINTER (item->master))) + continue; + if (item->parent > 0 && g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent))) + continue; + + g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex)); + g_array_index (result, NMPlatformLink, j++) = *item; + item->ifindex = 0; + found_something = TRUE; + } + + if (!found_something) { + /* there is a circle, pop the first (remaining) element from the list */ + g_warn_if_reached (); + item = &g_array_index (links, NMPlatformLink, first_idx); + + g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex)); + g_array_index (result, NMPlatformLink, j++) = *item; + item->ifindex = 0; + } + } while (j < nresult); + + g_hash_table_destroy (unseen); + g_array_free (links, TRUE); + + return result; +} + +/** + * nm_platform_link_get: + * @ifindex: ifindex of the link + * @link: (out): output NMPlatformLink structure. + * + * If a link with given @ifindex exists, fill the given NMPlatformLink + * structure. + * + * Returns: %TRUE, if such a link exists, %FALSE otherwise. + * If the link does not exist, the content of @link is undefined. + **/ +gboolean +nm_platform_link_get (int ifindex, NMPlatformLink *link) +{ + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (link, FALSE); + + g_return_val_if_fail (klass->link_get, FALSE); + return !!klass->link_get (platform, ifindex, link); +} + +/** + * nm_platform_link_add: + * @name: Interface name + * @type: Interface type + * @address: (allow-none): set the mac address of the link + * @address_len: the length of the @address + * + * Add a software interface. Sets platform->error to NM_PLATFORM_ERROR_EXISTS + * if interface is already already exists. Any link-changed ADDED signal will be + * emitted directly, before this function finishes. + */ +static gboolean +nm_platform_link_add (const char *name, NMLinkType type, const void *address, size_t address_len) +{ + reset_error (); + + g_return_val_if_fail (name, FALSE); + g_return_val_if_fail (klass->link_add, FALSE); + g_return_val_if_fail ( (address != NULL) ^ (address_len == 0) , FALSE); + + if (nm_platform_link_exists (name)) { + debug ("link: already exists"); + platform->error = NM_PLATFORM_ERROR_EXISTS; + return FALSE; + } + + return klass->link_add (platform, name, type, address, address_len); +} + +/** + * nm_platform_dummy_add: + * @name: New interface name + * + * Create a software ethernet-like interface + */ +gboolean +nm_platform_dummy_add (const char *name) +{ + g_return_val_if_fail (name, FALSE); + + debug ("link: adding dummy '%s'", name); + return nm_platform_link_add (name, NM_LINK_TYPE_DUMMY, NULL, 0); +} + +/** + * nm_platform_link_exists: + * @name: Interface name + * + * Returns: %TRUE if an interface of this name exists, %FALSE otherwise. + */ +gboolean +nm_platform_link_exists (const char *name) +{ + int ifindex = nm_platform_link_get_ifindex (name); + + reset_error(); + return ifindex > 0; +} + +/** + * nm_platform_link_delete: + * @ifindex: Interface index + * + * Delete a software interface. Sets platform->error to + * NM_PLATFORM_ERROR_NOT_FOUND if ifindex not available. + */ +gboolean +nm_platform_link_delete (int ifindex) +{ + const char *name; + + reset_error (); + + g_return_val_if_fail (klass->link_delete, FALSE); + + name = nm_platform_link_get_name (ifindex); + + if (!name) + return FALSE; + + debug ("link: deleting '%s' (%d)", name, ifindex); + return klass->link_delete (platform, ifindex); +} + +/** + * nm_platform_link_get_index: + * @name: Interface name + * + * Returns: The interface index corresponding to the given interface name + * or 0. Inteface name is owned by #NMPlatform, don't free it. + */ +int +nm_platform_link_get_ifindex (const char *name) +{ + int ifindex; + + reset_error (); + + g_return_val_if_fail (name, 0); + g_return_val_if_fail (klass->link_get_ifindex, 0); + + ifindex = klass->link_get_ifindex (platform, name); + + if (!ifindex) { + debug ("link not found: %s", name); + platform->error = NM_PLATFORM_ERROR_NOT_FOUND; + } + + return ifindex; +} + +/** + * nm_platform_link_get_name: + * @name: Interface name + * + * Returns: The interface name corresponding to the given interface index + * or %NULL. + */ +const char * +nm_platform_link_get_name (int ifindex) +{ + const char *name; + + reset_error (); + + g_return_val_if_fail (klass->link_get_name, NULL); + + name = klass->link_get_name (platform, ifindex); + + if (!name) { + debug ("link not found: %d", ifindex); + platform->error = NM_PLATFORM_ERROR_NOT_FOUND; + return FALSE; + } + + return name; +} + +/** + * nm_platform_link_get_type: + * @ifindex: Interface index. + * + * Returns: Link type constant as defined in nm-platform.h. On error, + * NM_LINK_TYPE_NONE is returned. + */ +NMLinkType +nm_platform_link_get_type (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (klass->link_get_type, NM_LINK_TYPE_NONE); + + return klass->link_get_type (platform, ifindex); +} + +/** + * nm_platform_link_get_type_name: + * @ifindex: Interface index. + * + * Returns: A string describing the type of link. In some cases this + * may be more specific than nm_platform_link_get_type(), but in + * other cases it may not. On error, %NULL is returned. + */ +const char * +nm_platform_link_get_type_name (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (klass->link_get_type_name, NULL); + + return klass->link_get_type_name (platform, ifindex); +} + +/** + * nm_platform_link_is_software: + * @ifindex: Interface index. + * + * Returns: %TRUE if ifindex belongs to a software interface, not backed by + * a physical device. + */ +gboolean +nm_platform_link_is_software (int ifindex) +{ + return (nm_platform_link_get_type (ifindex) & 0x10000); +} + +/** + * nm_platform_link_supports_slaves: + * @ifindex: Interface index. + * + * Returns: %TRUE if ifindex belongs to an interface capable of enslaving + * other interfaces. + */ +gboolean +nm_platform_link_supports_slaves (int ifindex) +{ + return (nm_platform_link_get_type (ifindex) & 0x20000); +} + +/** + * nm_platform_link_refresh: + * @ifindex: Interface index + * + * Reload the cache for ifindex synchronously. + */ +gboolean +nm_platform_link_refresh (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + + if (klass->link_refresh) + return klass->link_refresh (platform, ifindex); + + return TRUE; +} + +/** + * nm_platform_link_is_up: + * @ifindex: Interface index + * + * Check if the interface is up. + */ +gboolean +nm_platform_link_is_up (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_is_up, FALSE); + + return klass->link_is_up (platform, ifindex); +} + +/** + * nm_platform_link_is_connected: + * @ifindex: Interface index + * + * Check if the interface is connected. + */ +gboolean +nm_platform_link_is_connected (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_is_connected, FALSE); + + return klass->link_is_connected (platform, ifindex); +} + +/** + * nm_platform_link_uses_arp: + * @ifindex: Interface index + * + * Check if the interface is configured to use ARP. + */ +gboolean +nm_platform_link_uses_arp (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_uses_arp, FALSE); + + return klass->link_uses_arp (platform, ifindex); +} + +/** + * nm_platform_link_set_address: + * @ifindex: Interface index + * @address: The new MAC address + * + * Set interface MAC address. + */ +gboolean +nm_platform_link_set_address (int ifindex, gconstpointer address, size_t length) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (address, FALSE); + g_return_val_if_fail (length > 0, FALSE); + g_return_val_if_fail (klass->link_set_address, FALSE); + + debug ("link: setting '%s' (%d) hardware address", nm_platform_link_get_name (ifindex), ifindex); + return klass->link_set_address (platform, ifindex, address, length); +} + +/** + * nm_platform_link_get_address: + * @ifindex: Interface index + * @length: Pointer to a variable to store address length + * + * Saves interface hardware address to @address. + */ +gconstpointer +nm_platform_link_get_address (int ifindex, size_t *length) +{ + reset_error (); + + if (length) + *length = 0; + + g_return_val_if_fail (ifindex > 0, NULL); + g_return_val_if_fail (klass->link_get_address, NULL); + + return klass->link_get_address (platform, ifindex, length); +} + +gboolean +nm_platform_link_supports_carrier_detect (int ifindex) +{ + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_supports_carrier_detect, FALSE); + + return klass->link_supports_carrier_detect (platform, ifindex); +} + +gboolean +nm_platform_link_supports_vlans (int ifindex) +{ + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_supports_vlans, FALSE); + + return klass->link_supports_vlans (platform, ifindex); +} + +/** + * nm_platform_link_set_up: + * @ifindex: Interface index + * + * Bring the interface up. + */ +gboolean +nm_platform_link_set_up (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (klass->link_set_up, FALSE); + + debug ("link: setting up '%s' (%d)", nm_platform_link_get_name (ifindex), ifindex); + return klass->link_set_up (platform, ifindex); +} + +/** + * nm_platform_link_set_down: + * @ifindex: Interface index + * + * Take the interface down. + */ +gboolean +nm_platform_link_set_down (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (klass->link_set_down, FALSE); + + debug ("link: setting down '%s' (%d)", nm_platform_link_get_name (ifindex), ifindex); + return klass->link_set_down (platform, ifindex); +} + +/** + * nm_platform_link_set_arp: + * @ifindex: Interface index + * + * Enable ARP on the interface. + */ +gboolean +nm_platform_link_set_arp (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_set_arp, FALSE); + + debug ("link: setting arp '%s' (%d)", nm_platform_link_get_name (ifindex), ifindex); + return klass->link_set_arp (platform, ifindex); +} + +/** + * nm_platform_link_set_noarp: + * @ifindex: Interface index + * + * Disable ARP on the interface. + */ +gboolean +nm_platform_link_set_noarp (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_set_noarp, FALSE); + + debug ("link: setting noarp '%s' (%d)", nm_platform_link_get_name (ifindex), ifindex); + return klass->link_set_noarp (platform, ifindex); +} + +/** + * nm_platform_link_set_mtu: + * @ifindex: Interface index + * @mtu: The new MTU value + * + * Set interface MTU. + */ +gboolean +nm_platform_link_set_mtu (int ifindex, guint32 mtu) +{ + reset_error (); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (mtu > 0, FALSE); + g_return_val_if_fail (klass->link_set_mtu, FALSE); + + debug ("link: setting '%s' (%d) mtu %d", nm_platform_link_get_name (ifindex), ifindex, mtu); + return klass->link_set_mtu (platform, ifindex, mtu); +} + +/** + * nm_platform_link_get_mtu: + * @ifindex: Interface index + * + * Returns: MTU value for the interface or 0 on error. + */ +guint32 +nm_platform_link_get_mtu (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex >= 0, 0); + g_return_val_if_fail (klass->link_get_mtu, 0); + + return klass->link_get_mtu (platform, ifindex); +} + +/** + * nm_platform_link_get_mtu: + * @ifindex: Interface index + * + * Returns: physical port ID for the interface, or %NULL on error + * or if the interface has no physical port ID. + */ +char * +nm_platform_link_get_physical_port_id (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex >= 0, NULL); + g_return_val_if_fail (klass->link_get_physical_port_id, NULL); + + return klass->link_get_physical_port_id (platform, ifindex); +} + +/** + * nm_platform_link_get_wake_onlan: + * @ifindex: Interface index + * + * Returns: the "Wake-on-LAN" status for @ifindex. + */ +gboolean +nm_platform_link_get_wake_on_lan (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_get_wake_on_lan, FALSE); + + return klass->link_get_wake_on_lan (platform, ifindex); +} + +/** + * nm_platform_link_enslave: + * @master: Interface index of the master + * @slave: Interface index of the slave + * + * Enslave @slave to @master. + */ +gboolean +nm_platform_link_enslave (int master, int slave) +{ + reset_error (); + + g_assert (platform); + g_return_val_if_fail (master > 0, FALSE); + g_return_val_if_fail (slave> 0, FALSE); + g_return_val_if_fail (klass->link_enslave, FALSE); + + debug ("link: enslaving '%s' (%d) to master '%s' (%d)", + nm_platform_link_get_name (slave), slave, + nm_platform_link_get_name (master), master); + return klass->link_enslave (platform, master, slave); +} + +/** + * nm_platform_link_release: + * @master: Interface index of the master + * @slave: Interface index of the slave + * + * Release @slave from @master. + */ +gboolean +nm_platform_link_release (int master, int slave) +{ + reset_error (); + + g_assert (platform); + g_return_val_if_fail (master > 0, FALSE); + g_return_val_if_fail (slave > 0, FALSE); + g_return_val_if_fail (klass->link_release, FALSE); + + if (nm_platform_link_get_master (slave) != master) { + platform->error = NM_PLATFORM_ERROR_NOT_SLAVE; + return FALSE; + } + + debug ("link: releasing '%s' (%d) from master '%s' (%d)", + nm_platform_link_get_name (slave), slave, + nm_platform_link_get_name (master), master); + return klass->link_release (platform, master, slave); +} + +/** + * nm_platform_link_get_master: + * @slave: Interface index of the slave. + * + * Returns: Interfase index of the slave's master. + */ +int +nm_platform_link_get_master (int slave) +{ + reset_error (); + + g_assert (platform); + g_return_val_if_fail (slave >= 0, FALSE); + g_return_val_if_fail (klass->link_get_master, FALSE); + + if (!nm_platform_link_get_name (slave)) { + platform->error = NM_PLATFORM_ERROR_NOT_FOUND; + return 0; + } + return klass->link_get_master (platform, slave); +} + +/** + * nm_platform_bridge_add: + * @name: New interface name + * @address: (allow-none): set the mac address of the new bridge + * @address_len: the length of the @address + * + * Create a software bridge. + */ +gboolean +nm_platform_bridge_add (const char *name, const void *address, size_t address_len) +{ + debug ("link: adding bridge '%s'", name); + return nm_platform_link_add (name, NM_LINK_TYPE_BRIDGE, address, address_len); +} + +/** + * nm_platform_bond_add: + * @name: New interface name + * + * Create a software bonding device. + */ +gboolean +nm_platform_bond_add (const char *name) +{ + debug ("link: adding bond '%s'", name); + return nm_platform_link_add (name, NM_LINK_TYPE_BOND, NULL, 0); +} + +/** + * nm_platform_team_add: + * @name: New interface name + * + * Create a software teaming device. + */ +gboolean +nm_platform_team_add (const char *name) +{ + debug ("link: adding team '%s'", name); + return nm_platform_link_add (name, NM_LINK_TYPE_TEAM, NULL, 0); +} + +/** + * nm_platform_vlan_add: + * @name: New interface name + * @vlanid: VLAN identifier + * @vlanflags: VLAN flags from libnm-util + * + * Create a software VLAN device. + */ +gboolean +nm_platform_vlan_add (const char *name, int parent, int vlanid, guint32 vlanflags) +{ + reset_error (); + + g_assert (platform); + g_return_val_if_fail (parent >= 0, FALSE); + g_return_val_if_fail (vlanid >= 0, FALSE); + g_return_val_if_fail (name, FALSE); + g_return_val_if_fail (klass->vlan_add, FALSE); + + if (nm_platform_link_exists (name)) { + debug ("link already exists: %s", name); + platform->error = NM_PLATFORM_ERROR_EXISTS; + return FALSE; + } + + debug ("link: adding vlan '%s' parent %d vlanid %d vlanflags %x", + name, parent, vlanid, vlanflags); + return klass->vlan_add (platform, name, parent, vlanid, vlanflags); +} + +gboolean +nm_platform_master_set_option (int ifindex, const char *option, const char *value) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (option, FALSE); + g_return_val_if_fail (value, FALSE); + g_return_val_if_fail (klass->master_set_option, FALSE); + + return klass->master_set_option (platform, ifindex, option, value); +} + +char * +nm_platform_master_get_option (int ifindex, const char *option) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (option, FALSE); + g_return_val_if_fail (klass->master_set_option, FALSE); + + return klass->master_get_option (platform, ifindex, option); +} + +gboolean +nm_platform_slave_set_option (int ifindex, const char *option, const char *value) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (option, FALSE); + g_return_val_if_fail (value, FALSE); + g_return_val_if_fail (klass->slave_set_option, FALSE); + + return klass->slave_set_option (platform, ifindex, option, value); +} + +char * +nm_platform_slave_get_option (int ifindex, const char *option) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (option, FALSE); + g_return_val_if_fail (klass->slave_set_option, FALSE); + + return klass->slave_get_option (platform, ifindex, option); +} + +gboolean +nm_platform_vlan_get_info (int ifindex, int *parent, int *vlanid) +{ + reset_error (); + + g_assert (platform); + g_return_val_if_fail (klass->vlan_get_info, FALSE); + + if (parent) + *parent = 0; + if (vlanid) + *vlanid = 0; + + if (nm_platform_link_get_type (ifindex) != NM_LINK_TYPE_VLAN) + return FALSE; + + return klass->vlan_get_info (platform, ifindex, parent, vlanid); +} + +gboolean +nm_platform_vlan_set_ingress_map (int ifindex, int from, int to) +{ + reset_error (); + + g_assert (platform); + g_return_val_if_fail (klass->vlan_set_ingress_map, FALSE); + + debug ("link: setting vlan ingress map for %d from %d to %d", ifindex, from, to); + return klass->vlan_set_ingress_map (platform, ifindex, from, to); +} + +gboolean +nm_platform_vlan_set_egress_map (int ifindex, int from, int to) +{ + reset_error (); + + g_assert (platform); + g_return_val_if_fail (klass->vlan_set_egress_map, FALSE); + + debug ("link: setting vlan egress map for %d from %d to %d", ifindex, from, to); + return klass->vlan_set_egress_map (platform, ifindex, from, to); +} + +gboolean +nm_platform_infiniband_partition_add (int parent, int p_key) +{ + const char *parent_name; + char *name; + + reset_error (); + + g_return_val_if_fail (parent >= 0, FALSE); + g_return_val_if_fail (p_key >= 0, FALSE); + g_return_val_if_fail (klass->infiniband_partition_add, FALSE); + + if (nm_platform_link_get_type (parent) != NM_LINK_TYPE_INFINIBAND) { + platform->error = NM_PLATFORM_ERROR_WRONG_TYPE; + return FALSE; + } + + parent_name = nm_platform_link_get_name (parent); + name = g_strdup_printf ("%s.%04x", parent_name, p_key); + if (nm_platform_link_exists (name)) { + debug ("infiniband: already exists"); + platform->error = NM_PLATFORM_ERROR_EXISTS; + g_free (name); + return FALSE; + } + g_free (name); + + return klass->infiniband_partition_add (platform, parent, p_key); +} + +gboolean +nm_platform_veth_get_properties (int ifindex, NMPlatformVethProperties *props) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (props != NULL, FALSE); + + return klass->veth_get_properties (platform, ifindex, props); +} + +gboolean +nm_platform_tun_get_properties (int ifindex, NMPlatformTunProperties *props) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (props != NULL, FALSE); + + return klass->tun_get_properties (platform, ifindex, props); +} + +gboolean +nm_platform_macvlan_get_properties (int ifindex, NMPlatformMacvlanProperties *props) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (props != NULL, FALSE); + + return klass->macvlan_get_properties (platform, ifindex, props); +} + +gboolean +nm_platform_vxlan_get_properties (int ifindex, NMPlatformVxlanProperties *props) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (props != NULL, FALSE); + + return klass->vxlan_get_properties (platform, ifindex, props); +} + +gboolean +nm_platform_gre_get_properties (int ifindex, NMPlatformGreProperties *props) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (props != NULL, FALSE); + + return klass->gre_get_properties (platform, ifindex, props); +} + +gboolean +nm_platform_wifi_get_capabilities (int ifindex, NMDeviceWifiCapabilities *caps) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + + return klass->wifi_get_capabilities (platform, ifindex, caps); +} + +gboolean +nm_platform_wifi_get_bssid (int ifindex, struct ether_addr *bssid) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + + return klass->wifi_get_bssid (platform, ifindex, bssid); +} + +GByteArray * +nm_platform_wifi_get_ssid (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, NULL); + + return klass->wifi_get_ssid (platform, ifindex); +} + +guint32 +nm_platform_wifi_get_frequency (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, 0); + + return klass->wifi_get_frequency (platform, ifindex); +} + +int +nm_platform_wifi_get_quality (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, 0); + + return klass->wifi_get_quality (platform, ifindex); +} + +guint32 +nm_platform_wifi_get_rate (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, 0); + + return klass->wifi_get_rate (platform, ifindex); +} + +NM80211Mode +nm_platform_wifi_get_mode (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, NM_802_11_MODE_UNKNOWN); + + return klass->wifi_get_mode (platform, ifindex); +} + +void +nm_platform_wifi_set_mode (int ifindex, NM80211Mode mode) +{ + reset_error (); + + g_return_if_fail (ifindex > 0); + + klass->wifi_set_mode (platform, ifindex, mode); +} + +guint32 +nm_platform_wifi_find_frequency (int ifindex, const guint32 *freqs) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, 0); + g_return_val_if_fail (freqs != NULL, 0); + + return klass->wifi_find_frequency (platform, ifindex, freqs); +} + +void +nm_platform_wifi_indicate_addressing_running (int ifindex, gboolean running) +{ + reset_error (); + + g_return_if_fail (ifindex > 0); + + klass->wifi_indicate_addressing_running (platform, ifindex, running); +} + +guint32 +nm_platform_mesh_get_channel (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, 0); + + return klass->mesh_get_channel (platform, ifindex); +} + +gboolean +nm_platform_mesh_set_channel (int ifindex, guint32 channel) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + + return klass->mesh_set_channel (platform, ifindex, channel); +} + +gboolean +nm_platform_mesh_set_ssid (int ifindex, const GByteArray *ssid) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (ssid != NULL, FALSE); + + return klass->mesh_set_ssid (platform, ifindex, ssid); +} + +/******************************************************************/ + +GArray * +nm_platform_ip4_address_get_all (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, NULL); + g_return_val_if_fail (klass->ip4_address_get_all, NULL); + + return klass->ip4_address_get_all (platform, ifindex); +} + +GArray * +nm_platform_ip6_address_get_all (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, NULL); + g_return_val_if_fail (klass->ip6_address_get_all, NULL); + + return klass->ip6_address_get_all (platform, ifindex); +} + +gboolean +nm_platform_ip4_address_add (int ifindex, + in_addr_t address, + in_addr_t peer_address, + int plen, + guint32 lifetime, + guint32 preferred, + const char *label) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (plen > 0, FALSE); + g_return_val_if_fail (lifetime > 0, FALSE); + g_return_val_if_fail (preferred <= lifetime, FALSE); + g_return_val_if_fail (klass->ip4_address_add, FALSE); + g_return_val_if_fail (!label || strlen (label) < sizeof (((NMPlatformIP4Address *) NULL)->label), FALSE); + + if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) { + NMPlatformIP4Address addr = { 0 }; + + addr.ifindex = ifindex; + addr.address = address; + addr.peer_address = peer_address; + addr.plen = plen; + addr.timestamp = 0; /* set it at zero, which to_string will treat as *now* */ + addr.lifetime = lifetime; + addr.preferred = preferred; + if (label) + g_strlcpy (addr.label, label, sizeof (addr.label)); + + debug ("address: adding or updating IPv4 address: %s", nm_platform_ip4_address_to_string (&addr)); + } + return klass->ip4_address_add (platform, ifindex, address, peer_address, plen, lifetime, preferred, label); +} + +gboolean +nm_platform_ip6_address_add (int ifindex, + struct in6_addr address, + struct in6_addr peer_address, + int plen, + guint32 lifetime, + guint32 preferred, + guint flags) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (plen > 0, FALSE); + g_return_val_if_fail (lifetime > 0, FALSE); + g_return_val_if_fail (preferred <= lifetime, FALSE); + g_return_val_if_fail (klass->ip6_address_add, FALSE); + + if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) { + NMPlatformIP6Address addr = { 0 }; + + addr.ifindex = ifindex; + addr.address = address; + addr.peer_address = peer_address; + addr.plen = plen; + addr.timestamp = 0; /* set it to zero, which to_string will treat as *now* */ + addr.lifetime = lifetime; + addr.preferred = preferred; + addr.flags = flags; + + debug ("address: adding or updating IPv6 address: %s", nm_platform_ip6_address_to_string (&addr)); + } + return klass->ip6_address_add (platform, ifindex, address, peer_address, plen, lifetime, preferred, flags); +} + +gboolean +nm_platform_ip4_address_delete (int ifindex, in_addr_t address, int plen) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (plen > 0, FALSE); + g_return_val_if_fail (klass->ip4_address_delete, FALSE); + + debug ("address: deleting IPv4 address %s/%d", nm_utils_inet4_ntop (address, NULL), plen); + return klass->ip4_address_delete (platform, ifindex, address, plen); +} + +gboolean +nm_platform_ip6_address_delete (int ifindex, struct in6_addr address, int plen) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (plen > 0, FALSE); + g_return_val_if_fail (klass->ip6_address_delete, FALSE); + + debug ("address: deleting IPv6 address %s/%d", nm_utils_inet6_ntop (&address, NULL), plen); + return klass->ip6_address_delete (platform, ifindex, address, plen); +} + +gboolean +nm_platform_ip4_address_exists (int ifindex, in_addr_t address, int plen) +{ + reset_error (); + + g_return_val_if_fail (plen > 0, FALSE); + g_return_val_if_fail (klass->ip4_address_exists, FALSE); + + return klass->ip4_address_exists (platform, ifindex, address, plen); +} + +gboolean +nm_platform_ip6_address_exists (int ifindex, struct in6_addr address, int plen) +{ + reset_error (); + + g_return_val_if_fail (plen > 0, FALSE); + g_return_val_if_fail (klass->ip6_address_exists, FALSE); + + return klass->ip6_address_exists (platform, ifindex, address, plen); +} + +static gboolean +array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address *address) +{ + guint len = addresses ? addresses->len : 0; + guint i; + + for (i = 0; i < len; i++) { + NMPlatformIP4Address *candidate = &g_array_index (addresses, NMPlatformIP4Address, i); + + if (candidate->address == address->address && candidate->plen == address->plen) + return TRUE; + } + + return FALSE; +} + +static gboolean +array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address *address) +{ + guint len = addresses ? addresses->len : 0; + guint i; + + for (i = 0; i < len; i++) { + NMPlatformIP6Address *candidate = &g_array_index (addresses, NMPlatformIP6Address, i); + + if (IN6_ARE_ADDR_EQUAL (&candidate->address, &address->address) && candidate->plen == address->plen) + return TRUE; + } + + return FALSE; +} + +/** + * Takes a pair @timestamp and @duration, and returns the remaining duration based + * on the new timestamp @now. + */ +static guint32 +_rebase_relative_time_on_now (guint32 timestamp, guint32 duration, guint32 now, guint32 padding) +{ + gint64 t; + + if (duration == NM_PLATFORM_LIFETIME_PERMANENT) + return NM_PLATFORM_LIFETIME_PERMANENT; + + if (timestamp == 0) { + /* if the @timestamp is zero, assume it was just left unset and that the relative + * @duration starts counting from @now. This is convenient to construct an address + * and print it in nm_platform_ip4_address_to_string(). + * + * In general it does not make sense to set the @duration without anchoring at + * @timestamp because you don't know the absolute expiration time when looking + * at the address at a later moment. */ + timestamp = now; + } + + /* For timestamp > now, just accept it and calculate the expected(?) result. */ + t = (gint64) timestamp + (gint64) duration - (gint64) now; + + /* Optional padding to avoid potential races. */ + t += (gint64) padding; + + if (t <= 0) + return 0; + if (t >= NM_PLATFORM_LIFETIME_PERMANENT) + return NM_PLATFORM_LIFETIME_PERMANENT - 1; + return t; +} + +static gboolean +_address_get_lifetime (const NMPlatformIPAddress *address, guint32 now, guint32 padding, guint32 *out_lifetime, guint32 *out_preferred) +{ + gint32 lifetime, preferred; + + if (address->lifetime == 0) { + *out_lifetime = NM_PLATFORM_LIFETIME_PERMANENT; + *out_preferred = NM_PLATFORM_LIFETIME_PERMANENT; + } else { + lifetime = _rebase_relative_time_on_now (address->timestamp, address->lifetime, now, padding); + if (!lifetime) + return FALSE; + preferred = _rebase_relative_time_on_now (address->timestamp, address->preferred, now, padding); + + *out_lifetime = lifetime; + *out_preferred = MIN (preferred, lifetime); + + /* Assert that non-permanent addresses have a (positive) @timestamp. _rebase_relative_time_on_now() + * treats addresses with timestamp 0 as *now*. Addresses passed to _address_get_lifetime() always + * should have a valid @timestamp, otherwise on every re-sync, their lifetime will be extended anew. + */ + g_return_val_if_fail ( address->timestamp != 0 + || ( address->lifetime == NM_PLATFORM_LIFETIME_PERMANENT + && address->preferred == NM_PLATFORM_LIFETIME_PERMANENT), TRUE); + g_return_val_if_fail (preferred <= lifetime, TRUE); + } + return TRUE; +} + +/** + * nm_platform_ip4_address_sync: + * @ifindex: Interface index + * @known_addresses: List of addresses + * + * A convenience function to synchronize addresses for a specific interface + * with the least possible disturbance. It simply removes addresses that are + * not listed and adds addresses that are. + * + * Returns: %TRUE on success. + */ +gboolean +nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses) +{ + GArray *addresses; + NMPlatformIP4Address *address; + guint32 now = nm_utils_get_monotonic_timestamp_s (); + int i; + + /* Delete unknown addresses */ + addresses = nm_platform_ip4_address_get_all (ifindex); + for (i = 0; i < addresses->len; i++) { + address = &g_array_index (addresses, NMPlatformIP4Address, i); + + if (!array_contains_ip4_address (known_addresses, address)) + nm_platform_ip4_address_delete (ifindex, address->address, address->plen); + } + g_array_free (addresses, TRUE); + + if (!known_addresses) + return TRUE; + + /* Add missing addresses */ + for (i = 0; i < known_addresses->len; i++) { + const NMPlatformIP4Address *known_address = &g_array_index (known_addresses, NMPlatformIP4Address, i); + guint32 lifetime, preferred; + + /* add a padding of 5 seconds to avoid potential races. */ + if (!_address_get_lifetime ((NMPlatformIPAddress *) known_address, now, 5, &lifetime, &preferred)) + continue; + + if (!nm_platform_ip4_address_add (ifindex, known_address->address, known_address->peer_address, known_address->plen, lifetime, preferred, known_address->label)) + return FALSE; + } + + return TRUE; +} + +/** + * nm_platform_ip6_address_sync: + * @ifindex: Interface index + * @known_addresses: List of addresses + * + * A convenience function to synchronize addresses for a specific interface + * with the least possible disturbance. It simply removes addresses that are + * not listed and adds addresses that are. + * + * Returns: %TRUE on success. + */ +gboolean +nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses) +{ + GArray *addresses; + NMPlatformIP6Address *address; + guint32 now = nm_utils_get_monotonic_timestamp_s (); + int i; + + /* Delete unknown addresses */ + addresses = nm_platform_ip6_address_get_all (ifindex); + for (i = 0; i < addresses->len; i++) { + address = &g_array_index (addresses, NMPlatformIP6Address, i); + + /* Leave link local address management to the kernel */ + if (IN6_IS_ADDR_LINKLOCAL (&address->address)) + continue; + + if (!array_contains_ip6_address (known_addresses, address)) + nm_platform_ip6_address_delete (ifindex, address->address, address->plen); + } + g_array_free (addresses, TRUE); + + if (!known_addresses) + return TRUE; + + /* Add missing addresses */ + for (i = 0; i < known_addresses->len; i++) { + const NMPlatformIP6Address *known_address = &g_array_index (known_addresses, NMPlatformIP6Address, i); + guint32 lifetime, preferred; + + /* add a padding of 5 seconds to avoid potential races. */ + if (!_address_get_lifetime ((NMPlatformIPAddress *) known_address, now, 5, &lifetime, &preferred)) + continue; + + if (!nm_platform_ip6_address_add (ifindex, known_address->address, + known_address->peer_address, known_address->plen, + lifetime, preferred, known_address->flags)) + return FALSE; + } + + return TRUE; +} + +gboolean +nm_platform_address_flush (int ifindex) +{ + return nm_platform_ip4_address_sync (ifindex, NULL) + && nm_platform_ip6_address_sync (ifindex, NULL); +} + +/******************************************************************/ + +GArray * +nm_platform_ip4_route_get_all (int ifindex, gboolean include_default) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, NULL); + g_return_val_if_fail (klass->ip4_route_get_all, NULL); + + return klass->ip4_route_get_all (platform, ifindex, include_default); +} + +GArray * +nm_platform_ip6_route_get_all (int ifindex, gboolean include_default) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, NULL); + g_return_val_if_fail (klass->ip6_route_get_all, NULL); + + return klass->ip6_route_get_all (platform, ifindex, include_default); +} + +gboolean +nm_platform_ip4_route_add (int ifindex, NMPlatformSource source, + in_addr_t network, int plen, + in_addr_t gateway, int metric, int mss) +{ + reset_error (); + + g_return_val_if_fail (platform, FALSE); + g_return_val_if_fail (0 <= plen && plen <= 32, FALSE); + g_return_val_if_fail (metric >= 0, FALSE); + g_return_val_if_fail (mss >= 0, FALSE); + g_return_val_if_fail (klass->ip4_route_add, FALSE); + + if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) { + NMPlatformIP4Route route = { 0 }; + + route.ifindex = ifindex; + route.source = source; + route.network = network; + route.plen = plen; + route.gateway = gateway; + route.metric = metric; + route.mss = mss; + + debug ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route)); + } + return klass->ip4_route_add (platform, ifindex, source, network, plen, gateway, metric, mss); +} + +gboolean +nm_platform_ip6_route_add (int ifindex, NMPlatformSource source, + struct in6_addr network, int plen, struct in6_addr gateway, + int metric, int mss) +{ + g_return_val_if_fail (platform, FALSE); + g_return_val_if_fail (0 <= plen && plen <= 128, FALSE); + g_return_val_if_fail (metric >= 0, FALSE); + g_return_val_if_fail (mss >= 0, FALSE); + g_return_val_if_fail (klass->ip6_route_add, FALSE); + + if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) { + NMPlatformIP6Route route = { 0 }; + + route.ifindex = ifindex; + route.source = source; + route.network = network; + route.plen = plen; + route.gateway = gateway; + route.metric = metric; + route.mss = mss; + + debug ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route)); + } + return klass->ip6_route_add (platform, ifindex, source, network, plen, gateway, metric, mss); +} + +gboolean +nm_platform_ip4_route_delete (int ifindex, in_addr_t network, int plen, int metric) +{ + reset_error (); + + g_return_val_if_fail (platform, FALSE); + g_return_val_if_fail (klass->ip4_route_delete, FALSE); + + debug ("route: deleting IPv4 route %s/%d, metric=%d", nm_utils_inet4_ntop (network, NULL), plen, metric); + return klass->ip4_route_delete (platform, ifindex, network, plen, metric); +} + +gboolean +nm_platform_ip6_route_delete (int ifindex, struct in6_addr network, int plen, int metric) +{ + reset_error (); + + g_return_val_if_fail (platform, FALSE); + g_return_val_if_fail (klass->ip6_route_delete, FALSE); + + debug ("route: deleting IPv6 route %s/%d, metric=%d", nm_utils_inet6_ntop (&network, NULL), plen, metric); + return klass->ip6_route_delete (platform, ifindex, network, plen, metric); +} + +gboolean +nm_platform_ip4_route_exists (int ifindex, in_addr_t network, int plen, int metric) +{ + reset_error (); + + g_return_val_if_fail (platform, FALSE); + g_return_val_if_fail (klass->ip4_route_exists, FALSE); + + return klass->ip4_route_exists (platform,ifindex, network, plen, metric); +} + +gboolean +nm_platform_ip6_route_exists (int ifindex, struct in6_addr network, int plen, int metric) +{ + reset_error (); + + g_return_val_if_fail (platform, FALSE); + g_return_val_if_fail (klass->ip6_route_exists, FALSE); + + return klass->ip6_route_exists (platform, ifindex, network, plen, metric); +} + +static gboolean +array_contains_ip4_route (const GArray *routes, const NMPlatformIP4Route *route) +{ + guint len = routes ? routes->len : 0; + guint i; + + for (i = 0; i < len; i++) { + NMPlatformIP4Route *c = &g_array_index (routes, NMPlatformIP4Route, i); + + if (route->network == c->network && + route->plen == c->plen && + route->gateway == c->gateway && + route->metric == c->metric) + return TRUE; + } + + return FALSE; +} + +static gboolean +array_contains_ip6_route (const GArray *routes, const NMPlatformIP6Route *route) +{ + guint len = routes ? routes->len : 0; + guint i; + + for (i = 0; i < len; i++) { + NMPlatformIP6Route *c = &g_array_index (routes, NMPlatformIP6Route, i); + + if (IN6_ARE_ADDR_EQUAL (&route->network, &c->network) && + route->plen == c->plen && + IN6_ARE_ADDR_EQUAL (&route->gateway, &c->gateway) && + route->metric == c->metric) + return TRUE; + } + + return FALSE; +} + +/** + * nm_platform_ip4_route_sync: + * @ifindex: Interface index + * @known_routes: List of routes + * + * A convenience function to synchronize routes for a specific interface + * with the least possible disturbance. It simply removes routes that are + * not listed and adds routes that are. + * + * Returns: %TRUE on success. + */ +gboolean +nm_platform_ip4_route_sync (int ifindex, const GArray *known_routes) +{ + GArray *routes; + NMPlatformIP4Route *route; + const NMPlatformIP4Route *known_route; + gboolean success; + int i, i_type; + + /* Delete unknown routes */ + routes = nm_platform_ip4_route_get_all (ifindex, FALSE); + for (i = 0; i < routes->len; i++) { + route = &g_array_index (routes, NMPlatformIP4Route, i); + + if (!array_contains_ip4_route (known_routes, route)) + nm_platform_ip4_route_delete (ifindex, route->network, route->plen, route->metric); + } + + if (!known_routes) { + g_array_free (routes, TRUE); + return TRUE; + } + + /* Add missing routes */ + for (i_type = 0, success = TRUE; i_type < 2 && success; i_type++) { + for (i = 0; i < known_routes->len && success; i++) { + known_route = &g_array_index (known_routes, NMPlatformIP4Route, i); + + if ((known_route->gateway == 0) ^ (i_type != 0)) { + /* Make two runs over the list of routes. On the first, only add + * device routes, on the second the others (gateway routes). */ + continue; + } + + /* Ignore routes that already exist */ + if (!array_contains_ip4_route (routes, known_route)) { + success = nm_platform_ip4_route_add (ifindex, + known_route->source, + known_route->network, + known_route->plen, + known_route->gateway, + known_route->metric, + known_route->mss); + if (!success && known_route->source < NM_PLATFORM_SOURCE_USER) { + nm_log_dbg (LOGD_PLATFORM, "ignore error adding IPv4 route to kernel: %s", + nm_platform_ip4_route_to_string (known_route)); + success = TRUE; + } + } + } + } + + g_array_free (routes, TRUE); + return success; +} + +/** + * nm_platform_ip6_route_sync: + * @ifindex: Interface index + * @known_routes: List of routes + * + * A convenience function to synchronize routes for a specific interface + * with the least possible disturbance. It simply removes routes that are + * not listed and adds routes that are. + * + * Returns: %TRUE on success. + */ +gboolean +nm_platform_ip6_route_sync (int ifindex, const GArray *known_routes) +{ + GArray *routes; + NMPlatformIP6Route *route; + const NMPlatformIP6Route *known_route; + gboolean success; + int i, i_type; + + /* Delete unknown routes */ + routes = nm_platform_ip6_route_get_all (ifindex, FALSE); + for (i = 0; i < routes->len; i++) { + route = &g_array_index (routes, NMPlatformIP6Route, i); + route->ifindex = 0; + + if (!array_contains_ip6_route (known_routes, route)) + nm_platform_ip6_route_delete (ifindex, route->network, route->plen, route->metric); + } + + if (!known_routes) { + g_array_free (routes, TRUE); + return TRUE; + } + + /* Add missing routes */ + for (i_type = 0, success = TRUE; i_type < 2 && success; i_type++) { + for (i = 0; i < known_routes->len && success; i++) { + known_route = &g_array_index (known_routes, NMPlatformIP6Route, i); + + if (IN6_IS_ADDR_UNSPECIFIED (&known_route->gateway) ^ (i_type != 0)) { + /* Make two runs over the list of routes. On the first, only add + * device routes, on the second the others (gateway routes). */ + continue; + } + + /* Ignore routes that already exist */ + if (!array_contains_ip6_route (routes, known_route)) { + success = nm_platform_ip6_route_add (ifindex, + known_route->source, + known_route->network, + known_route->plen, + known_route->gateway, + known_route->metric, + known_route->mss); + if (!success && known_route->source < NM_PLATFORM_SOURCE_USER) { + nm_log_dbg (LOGD_PLATFORM, "ignore error adding IPv6 route to kernel: %s", + nm_platform_ip6_route_to_string (known_route)); + success = TRUE; + } + } + } + } + + g_array_free (routes, TRUE); + return success; +} + +gboolean +nm_platform_route_flush (int ifindex) +{ + return nm_platform_ip4_route_sync (ifindex, NULL) + && nm_platform_ip6_route_sync (ifindex, NULL); +} + +/******************************************************************/ + +static const char * +source_to_string (NMPlatformSource source) +{ + switch (source) { + case NM_PLATFORM_SOURCE_KERNEL: + return "kernel"; + case NM_PLATFORM_SOURCE_SHARED: + return "shared"; + case NM_PLATFORM_SOURCE_IP4LL: + return "ipv4ll"; + case NM_PLATFORM_SOURCE_PPP: + return "ppp"; + case NM_PLATFORM_SOURCE_WWAN: + return "wwan"; + case NM_PLATFORM_SOURCE_VPN: + return "vpn"; + case NM_PLATFORM_SOURCE_DHCP: + return "dhcp"; + case NM_PLATFORM_SOURCE_RDISC: + return "rdisc"; + case NM_PLATFORM_SOURCE_USER: + return "user"; + default: + break; + } + return "unknown"; +} + +#define TO_STRING_DEV_BUF_SIZE (5+15+1) +static void +_to_string_dev (int ifindex, char *buf, size_t size) +{ + g_assert (buf && size >= TO_STRING_DEV_BUF_SIZE); + + if (ifindex){ + const char *name = ifindex > 0 ? nm_platform_link_get_name (ifindex) : NULL; + + strcpy (buf, " dev "); + buf += 5; + size -= 5; + + if (name) + g_strlcpy (buf, name, size); + else + g_snprintf (buf, size, "%d", ifindex); + } else + buf[0] = 0; +} + +static const char * +_lifetime_to_string (guint32 timestamp, guint32 lifetime, gint32 now, char *buf, size_t buf_size) +{ + if (lifetime == NM_PLATFORM_LIFETIME_PERMANENT) + return "forever"; + + g_snprintf (buf, buf_size, "%usec", + _rebase_relative_time_on_now (timestamp, lifetime, now, 0)); + return buf; +} + + +static const char * +_lifetime_summary_to_string (gint32 now, guint32 timestamp, guint32 preferred, guint32 lifetime, char *buf, size_t buf_size) +{ + g_snprintf (buf, buf_size, " lifetime %d-%u[%u,%u]", + (signed) now, (unsigned) timestamp, (unsigned) preferred, (unsigned) lifetime); + return buf; +} + +static char to_string_buffer[256]; + +const char * +nm_platform_link_to_string (const NMPlatformLink *link) +{ + char master[20]; + char parent[20]; + char *driver, *udi, *type; + GString *str; + + if (!link) + return "(unknown link)"; + + str = g_string_new (NULL); + if (!link->arp) + g_string_append (str, "NOARP,"); + if (link->up) + g_string_append (str, "UP"); + else + g_string_append (str, "DOWN"); + if (link->connected) + g_string_append (str, ",LOWER_UP"); + + if (link->master) + g_snprintf (master, sizeof (master), " master %d", link->master); + else + master[0] = 0; + + if (link->parent) + g_snprintf (parent, sizeof (master), "@%d", link->parent); + else + parent[0] = 0; + + driver = link->driver ? g_strdup_printf (" driver '%s'", link->driver) : NULL; + udi = link->udi ? g_strdup_printf (" udi '%s'", link->udi) : NULL; + type = link->type_name ? NULL : g_strdup_printf ("(%d)", link->type); + + g_snprintf (to_string_buffer, sizeof (to_string_buffer), "%d: %s%s <%s> mtu %d%s %s%s%s", + link->ifindex, link->name, parent, str->str, + link->mtu, master, link->type_name ? link->type_name : type, + driver ? driver : "", udi ? udi : ""); + g_string_free (str, TRUE); + g_free (driver); + g_free (udi); + g_free (type); + return to_string_buffer; +} + +/** + * nm_platform_ip4_address_to_string: + * @route: pointer to NMPlatformIP4Address address structure + * + * A method for converting an address struct into a string representation. + * + * Example output: "" + * + * Returns: a string representation of the address. The returned string + * is an internal buffer, so do not keep or free the returned string. + * Also, this function is not thread safe. + */ +const char * +nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address) +{ + char s_address[INET_ADDRSTRLEN]; + char s_peer[INET_ADDRSTRLEN]; + char str_dev[TO_STRING_DEV_BUF_SIZE]; + char str_label[32]; + char str_lft[30], str_pref[30], str_time[50]; + char *str_peer = NULL; + const char *str_lft_p, *str_pref_p, *str_time_p; + gint32 now = nm_utils_get_monotonic_timestamp_s (); + + g_return_val_if_fail (address, "(unknown)"); + + inet_ntop (AF_INET, &address->address, s_address, sizeof (s_address)); + + if (address->peer_address) { + inet_ntop (AF_INET, &address->peer_address, s_peer, sizeof (s_peer)); + str_peer = g_strconcat (" ptp ", s_peer, NULL); + } + + _to_string_dev (address->ifindex, str_dev, sizeof (str_dev)); + + if (*address->label) + g_snprintf (str_label, sizeof (str_label), " label %s", address->label); + else + str_label[0] = 0; + + str_lft_p = _lifetime_to_string (address->timestamp, + address->lifetime ? address->lifetime : NM_PLATFORM_LIFETIME_PERMANENT, + now, str_lft, sizeof (str_lft)), + str_pref_p = (address->lifetime == address->preferred) + ? str_lft_p + : ( _lifetime_to_string (address->timestamp, + address->lifetime ? MIN (address->preferred, address->lifetime) : NM_PLATFORM_LIFETIME_PERMANENT, + now, str_pref, sizeof (str_pref)) ); + str_time_p = _lifetime_summary_to_string (now, address->timestamp, address->preferred, address->lifetime, str_time, sizeof (str_time)); + + g_snprintf (to_string_buffer, sizeof (to_string_buffer), "%s/%d lft %s pref %s%s%s%s%s src %s", + s_address, address->plen, str_lft_p, str_pref_p, str_time_p, + str_peer ? str_peer : "", + str_dev, + str_label, + source_to_string (address->source)); + g_free (str_peer); + return to_string_buffer; +} + +/** + * nm_platform_addr_flags2str: wrapper for rtnl_addr_flags2str(), + * which might not yet support some recent address flags. + **/ +void +nm_platform_addr_flags2str (int flags, char *buf, size_t size) +{ + rtnl_addr_flags2str(flags, buf, size); + + /* There are two recent flags IFA_F_MANAGETEMPADDR and IFA_F_NOPREFIXROUTE. + * If libnl does not yet support them, add them by hand. + * These two flags were introduced together with the extended ifa_flags, + * so, check for that. + */ + if ((flags & IFA_F_MANAGETEMPADDR) && !nm_platform_check_support_libnl_extended_ifa_flags ()) { + strncat (buf, buf[0] ? "," IFA_F_MANAGETEMPADDR_STR : IFA_F_MANAGETEMPADDR_STR, + size - strlen (buf) - 1); + } + if ((flags & IFA_F_NOPREFIXROUTE) && !nm_platform_check_support_libnl_extended_ifa_flags ()) { + strncat (buf, buf[0] ? "," IFA_F_NOPREFIXROUTE_STR : IFA_F_NOPREFIXROUTE_STR, + size - strlen (buf) - 1); + } +} + +/** + * nm_platform_ip6_address_to_string: + * @route: pointer to NMPlatformIP6Address address structure + * + * A method for converting an address struct into a string representation. + * + * Example output: "2001:db8:0:f101::1/64 lft 4294967295 pref 4294967295 time 16922666 on dev em1" + * + * Returns: a string representation of the address. The returned string + * is an internal buffer, so do not keep or free the returned string. + * Also, this function is not thread safe. + */ +const char * +nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address) +{ + char s_flags[256]; + char s_address[INET6_ADDRSTRLEN]; + char s_peer[INET6_ADDRSTRLEN]; + char str_lft[30], str_pref[30], str_time[50]; + char str_dev[TO_STRING_DEV_BUF_SIZE]; + char *str_flags; + char *str_peer = NULL; + const char *str_lft_p, *str_pref_p, *str_time_p; + gint32 now = nm_utils_get_monotonic_timestamp_s (); + + g_return_val_if_fail (address, "(unknown)"); + + inet_ntop (AF_INET6, &address->address, s_address, sizeof (s_address)); + + if (!IN6_IS_ADDR_UNSPECIFIED (&address->peer_address)) { + inet_ntop (AF_INET6, &address->peer_address, s_peer, sizeof (s_peer)); + str_peer = g_strconcat (" ptp ", s_peer, NULL); + } + + _to_string_dev (address->ifindex, str_dev, sizeof (str_dev)); + + nm_platform_addr_flags2str (address->flags, s_flags, sizeof (s_flags)); + + str_flags = s_flags[0] ? g_strconcat (" flags ", s_flags, NULL) : NULL; + + str_lft_p = _lifetime_to_string (address->timestamp, + address->lifetime ? address->lifetime : NM_PLATFORM_LIFETIME_PERMANENT, + now, str_lft, sizeof (str_lft)), + str_pref_p = (address->lifetime == address->preferred) + ? str_lft_p + : ( _lifetime_to_string (address->timestamp, + address->lifetime ? MIN (address->preferred, address->lifetime) : NM_PLATFORM_LIFETIME_PERMANENT, + now, str_pref, sizeof (str_pref)) ); + str_time_p = _lifetime_summary_to_string (now, address->timestamp, address->preferred, address->lifetime, str_time, sizeof (str_time)); + + g_snprintf (to_string_buffer, sizeof (to_string_buffer), "%s/%d lft %s pref %s%s%s%s%s src %s", + s_address, address->plen, str_lft_p, str_pref_p, str_time_p, + str_peer ? str_peer : "", + str_dev, + str_flags ? str_flags : "", + source_to_string (address->source)); + g_free (str_flags); + g_free (str_peer); + return to_string_buffer; +} + +/** + * nm_platform_ip4_route_to_string: + * @route: pointer to NMPlatformIP4Route route structure + * + * A method for converting a route struct into a string representation. + * + * Example output: "192.168.1.0/24 via 0.0.0.0 dev em1 metric 0 mss 0" + * + * Returns: a string representation of the route. The returned string + * is an internal buffer, so do not keep or free the returned string. + * Also, this function is not thread safe. + */ +const char * +nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route) +{ + char s_network[INET_ADDRSTRLEN], s_gateway[INET_ADDRSTRLEN]; + char str_dev[TO_STRING_DEV_BUF_SIZE]; + + g_return_val_if_fail (route, "(unknown)"); + + inet_ntop (AF_INET, &route->network, s_network, sizeof(s_network)); + inet_ntop (AF_INET, &route->gateway, s_gateway, sizeof(s_gateway)); + + _to_string_dev (route->ifindex, str_dev, sizeof (str_dev)); + + g_snprintf (to_string_buffer, sizeof (to_string_buffer), "%s/%d via %s%s metric %u mss %u src %s", + s_network, route->plen, s_gateway, + str_dev, + route->metric, route->mss, + source_to_string (route->source)); + return to_string_buffer; +} + +/** + * nm_platform_ip6_route_to_string: + * @route: pointer to NMPlatformIP6Route route structure + * + * A method for converting a route struct into a string representation. + * + * Example output: "ff02::fb/128 via :: dev em1 metric 0" + * + * Returns: a string representation of the route. The returned string + * is an internal buffer, so do not keep or free the returned string. + * Also, this function is not thread safe. + */ +const char * +nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route) +{ + char s_network[INET6_ADDRSTRLEN], s_gateway[INET6_ADDRSTRLEN]; + char str_dev[TO_STRING_DEV_BUF_SIZE]; + + g_return_val_if_fail (route, "(unknown)"); + + inet_ntop (AF_INET6, &route->network, s_network, sizeof(s_network)); + inet_ntop (AF_INET6, &route->gateway, s_gateway, sizeof(s_gateway)); + + _to_string_dev (route->ifindex, str_dev, sizeof (str_dev)); + + g_snprintf (to_string_buffer, sizeof (to_string_buffer), "%s/%d via %s%s metric %u mss %u src %s", + s_network, route->plen, s_gateway, + str_dev, + route->metric, route->mss, + source_to_string (route->source)); + return to_string_buffer; +} + +#define _CMP_POINTER(a, b) \ + G_STMT_START { \ + if ((a) == (b)) \ + return 0; \ + if (!(a)) \ + return -1; \ + if (!(b)) \ + return 1; \ + } G_STMT_END + +#define _CMP_FIELD(a, b, field) \ + G_STMT_START { \ + if (((a)->field) != ((b)->field)) \ + return (((a)->field) < ((b)->field)) ? -1 : 1; \ + } G_STMT_END + +#define _CMP_FIELD_STR(a, b, field) \ + G_STMT_START { \ + int c = strcmp ((a)->field, (b)->field); \ + if (c != 0) \ + return c < 0 ? -1 : 1; \ + } G_STMT_END + +#define _CMP_FIELD_STR0(a, b, field) \ + G_STMT_START { \ + int c = g_strcmp0 ((a)->field, (b)->field); \ + if (c != 0) \ + return c < 0 ? -1 : 1; \ + } G_STMT_END + +#define _CMP_FIELD_MEMCMP(a, b, field) \ + G_STMT_START { \ + int c = memcmp (&((a)->field), &((b)->field), \ + sizeof ((a)->field)); \ + if (c != 0) \ + return c < 0 ? -1 : 1; \ + } G_STMT_END + +int +nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b) +{ + _CMP_POINTER (a, b); + _CMP_FIELD (a, b, type); + _CMP_FIELD_STR (a, b, name); + _CMP_FIELD (a, b, master); + _CMP_FIELD (a, b, parent); + _CMP_FIELD (a, b, up); + _CMP_FIELD (a, b, connected); + _CMP_FIELD (a, b, arp); + _CMP_FIELD (a, b, mtu); + _CMP_FIELD_STR0 (a, b, type_name); + _CMP_FIELD_STR0 (a, b, udi); + _CMP_FIELD_STR0 (a, b, driver); + return 0; +} + +int +nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b) +{ + _CMP_POINTER (a, b); + _CMP_FIELD (a, b, ifindex); + _CMP_FIELD (a, b, source); + _CMP_FIELD (a, b, address); + _CMP_FIELD (a, b, peer_address); + _CMP_FIELD (a, b, plen); + _CMP_FIELD (a, b, timestamp); + _CMP_FIELD (a, b, lifetime); + _CMP_FIELD (a, b, preferred); + _CMP_FIELD_STR (a, b, label); + return 0; +} + +int +nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b) +{ + _CMP_POINTER (a, b); + _CMP_FIELD (a, b, ifindex); + _CMP_FIELD (a, b, source); + _CMP_FIELD_MEMCMP (a, b, address); + _CMP_FIELD_MEMCMP (a, b, peer_address); + _CMP_FIELD (a, b, plen); + _CMP_FIELD (a, b, timestamp); + _CMP_FIELD (a, b, lifetime); + _CMP_FIELD (a, b, preferred); + _CMP_FIELD (a, b, flags); + return 0; +} + +int +nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b) +{ + _CMP_POINTER (a, b); + _CMP_FIELD (a, b, ifindex); + _CMP_FIELD (a, b, source); + _CMP_FIELD (a, b, network); + _CMP_FIELD (a, b, plen); + _CMP_FIELD (a, b, gateway); + _CMP_FIELD (a, b, metric); + _CMP_FIELD (a, b, mss); + return 0; +} + +int +nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b) +{ + _CMP_POINTER (a, b); + _CMP_FIELD (a, b, ifindex); + _CMP_FIELD (a, b, source); + _CMP_FIELD_MEMCMP (a, b, network); + _CMP_FIELD (a, b, plen); + _CMP_FIELD_MEMCMP (a, b, gateway); + _CMP_FIELD (a, b, metric); + _CMP_FIELD (a, b, mss); + return 0; +} + +#undef _CMP_FIELD +#undef _CMP_FIELD_MEMCMP + +/** + * nm_platform_ip_address_cmp_expiry: + * @a: a NMPlatformIPAddress to compare + * @b: the other NMPlatformIPAddress to compare + * + * Compares two addresses and returns which one has a longer remaining lifetime. + * If both addresses have the same lifetime, look at the remaining preferred time. + * + * For comparison, only the timestamp, lifetime and preferred fields are considered. + * If they compare equal (== 0), their other fields were not considered. + * + * Returns: -1, 0, or 1 according to the comparison + **/ +int +nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatformIPAddress *b) +{ + gint64 ta = 0, tb = 0; + + _CMP_POINTER (a, b); + + if (a->lifetime == NM_PLATFORM_LIFETIME_PERMANENT || a->lifetime == 0) + ta = G_MAXINT64; + else if (a->timestamp) + ta = ((gint64) a->timestamp) + a->lifetime; + + if (b->lifetime == NM_PLATFORM_LIFETIME_PERMANENT || b->lifetime == 0) + tb = G_MAXINT64; + else if (b->timestamp) + tb = ((gint64) b->timestamp) + b->lifetime; + + if (ta == tb) { + /* if the lifetime is equal, compare the preferred time. */ + ta = tb = 0; + + if (a->preferred == NM_PLATFORM_LIFETIME_PERMANENT || a->lifetime == 0 /* liftime==0 means permanent! */) + ta = G_MAXINT64; + else if (a->timestamp) + ta = ((gint64) a->timestamp) + a->preferred; + + if (b->preferred == NM_PLATFORM_LIFETIME_PERMANENT|| b->lifetime == 0) + tb = G_MAXINT64; + else if (b->timestamp) + tb = ((gint64) b->timestamp) + b->preferred; + + if (ta == tb) + return 0; + } + + return ta < tb ? -1 : 1; +} + +#undef _CMP_POINTER + +static const char * +_change_type_to_string (NMPlatformSignalChangeType change_type) +{ + switch (change_type) { + case NM_PLATFORM_SIGNAL_ADDED: + return "added"; + case NM_PLATFORM_SIGNAL_CHANGED: + return "changed"; + case NM_PLATFORM_SIGNAL_REMOVED: + return "removed"; + default: + g_return_val_if_reached ("UNKNOWN"); + } +} + +static void +log_link (NMPlatform *p, int ifindex, NMPlatformLink *device, NMPlatformSignalChangeType change_type, gpointer user_data) +{ + + debug ("signal: link %7s: %s", _change_type_to_string (change_type), nm_platform_link_to_string (device)); +} + +static void +log_ip4_address (NMPlatform *p, int ifindex, NMPlatformIP4Address *address, NMPlatformSignalChangeType change_type, gpointer user_data) +{ + debug ("signal: address 4 %7s: %s", _change_type_to_string (change_type), nm_platform_ip4_address_to_string (address)); +} + +static void +log_ip6_address (NMPlatform *p, int ifindex, NMPlatformIP6Address *address, NMPlatformSignalChangeType change_type, gpointer user_data) +{ + debug ("signal: address 6 %7s: %s", _change_type_to_string (change_type), nm_platform_ip6_address_to_string (address)); +} + +static void +log_ip4_route (NMPlatform *p, int ifindex, NMPlatformIP4Route *route, NMPlatformSignalChangeType change_type, gpointer user_data) +{ + debug ("signal: route 4 %7s: %s", _change_type_to_string (change_type), nm_platform_ip4_route_to_string (route)); +} + +static void +log_ip6_route (NMPlatform *p, int ifindex, NMPlatformIP6Route *route, NMPlatformSignalChangeType change_type, gpointer user_data) +{ + debug ("signal: route 6 %7s: %s", _change_type_to_string (change_type), nm_platform_ip6_route_to_string (route)); +} + +/******************************************************************/ + +static void +nm_platform_init (NMPlatform *object) +{ +} + +#define SIGNAL(signal_id, method) signals[signal_id] = \ + g_signal_new_class_handler (NM_PLATFORM_ ## signal_id, \ + G_OBJECT_CLASS_TYPE (object_class), \ + G_SIGNAL_RUN_FIRST, \ + G_CALLBACK (method), \ + NULL, NULL, NULL, \ + G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_POINTER, NM_TYPE_PLATFORM_SIGNAL_CHANGE_TYPE, NM_TYPE_PLATFORM_REASON); + +static void +nm_platform_class_init (NMPlatformClass *platform_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (platform_class); + + /* Signals */ + SIGNAL (SIGNAL_LINK_CHANGED, log_link) + SIGNAL (SIGNAL_IP4_ADDRESS_CHANGED, log_ip4_address) + SIGNAL (SIGNAL_IP6_ADDRESS_CHANGED, log_ip6_address) + SIGNAL (SIGNAL_IP4_ROUTE_CHANGED, log_ip4_route) + SIGNAL (SIGNAL_IP6_ROUTE_CHANGED, log_ip6_route) +} diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h new file mode 100644 index 00000000..96b6cfab --- /dev/null +++ b/src/platform/nm-platform.h @@ -0,0 +1,634 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-platform.c - Handle runtime kernel networking configuration + * + * 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, 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 - 2010 Red Hat, Inc. + */ + +#ifndef NM_PLATFORM_H +#define NM_PLATFORM_H + +#include <glib-object.h> +#include "nm-glib-compat.h" +#include <netinet/in.h> +#include <net/ethernet.h> +#include <linux/if.h> +#include <linux/if_addr.h> + +#include <NetworkManager.h> + +#define NM_TYPE_PLATFORM (nm_platform_get_type ()) +#define NM_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PLATFORM, NMPlatform)) +#define NM_PLATFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_PLATFORM, NMPlatformClass)) +#define NM_IS_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_PLATFORM)) +#define NM_IS_PLATFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_PLATFORM)) +#define NM_PLATFORM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_PLATFORM, NMPlatformClass)) + +/******************************************************************/ + +/* workaround for older libnl version, that does not define these flags. */ +#ifndef IFA_F_MANAGETEMPADDR +#define IFA_F_MANAGETEMPADDR 0x100 +#endif +#ifndef IFA_F_NOPREFIXROUTE +#define IFA_F_NOPREFIXROUTE 0x200 +#endif + +typedef enum { + /* no error specified, sometimes this means the arguments were wrong */ + NM_PLATFORM_ERROR_NONE, + /* object was not found */ + NM_PLATFORM_ERROR_NOT_FOUND, + /* object already exists */ + NM_PLATFORM_ERROR_EXISTS, + /* object is wrong type */ + NM_PLATFORM_ERROR_WRONG_TYPE, + /* object is not a slave */ + NM_PLATFORM_ERROR_NOT_SLAVE, + /* firmware is not found */ + NM_PLATFORM_ERROR_NO_FIRMWARE +} NMPlatformError; + +typedef enum { + NM_PLATFORM_REASON_NONE, + /* Event was requested by NetworkManager. */ + NM_PLATFORM_REASON_INTERNAL, + /* Event came from the kernel. */ + NM_PLATFORM_REASON_EXTERNAL, + /* Event is a result of cache checking and cleanups. */ + NM_PLATFORM_REASON_CACHE_CHECK +} NMPlatformReason; + +typedef enum { + /* Please don't interpret type numbers outside nm-platform and use functions + * like nm_platform_link_is_software() and nm_platform_supports_slaves(). + * + * type & 0x10000 -> Software device type + * type & 0x20000 -> Type supports slaves + */ + + /* No type, used as error value */ + NM_LINK_TYPE_NONE, + + /* Unknown type */ + NM_LINK_TYPE_UNKNOWN, + + /* Hardware types */ + NM_LINK_TYPE_ETHERNET, + NM_LINK_TYPE_INFINIBAND, + NM_LINK_TYPE_OLPC_MESH, + NM_LINK_TYPE_WIFI, + NM_LINK_TYPE_WWAN_ETHERNET, /* WWAN pseudo-ethernet */ + NM_LINK_TYPE_WIMAX, + + /* Software types */ + NM_LINK_TYPE_DUMMY = 0x10000, + NM_LINK_TYPE_GRE, + NM_LINK_TYPE_GRETAP, + NM_LINK_TYPE_IFB, + NM_LINK_TYPE_LOOPBACK, + NM_LINK_TYPE_MACVLAN, + NM_LINK_TYPE_MACVTAP, + NM_LINK_TYPE_OPENVSWITCH, + NM_LINK_TYPE_TAP, + NM_LINK_TYPE_TUN, + NM_LINK_TYPE_VETH, + NM_LINK_TYPE_VLAN, + NM_LINK_TYPE_VXLAN, + + /* Software types with slaves */ + NM_LINK_TYPE_BRIDGE = 0x10000 | 0x20000, + NM_LINK_TYPE_BOND, + NM_LINK_TYPE_TEAM, +} NMLinkType; + +#define __NMPlatformObject_COMMON \ + int ifindex; \ + ; + +typedef struct { + __NMPlatformObject_COMMON; + char name[IFNAMSIZ]; + NMLinkType type; + const char *type_name; + const char *udi; + const char *driver; + int master; + int parent; + gboolean up; + gboolean connected; + gboolean arp; + guint mtu; +} NMPlatformLink; + +typedef enum { + NM_PLATFORM_SIGNAL_ADDED, + NM_PLATFORM_SIGNAL_CHANGED, + NM_PLATFORM_SIGNAL_REMOVED, +} NMPlatformSignalChangeType; + +#define NM_PLATFORM_LIFETIME_PERMANENT G_MAXUINT32 + +typedef enum { + /* In priority order; higher number == higher priority */ + NM_PLATFORM_SOURCE_UNKNOWN, + NM_PLATFORM_SOURCE_KERNEL, + NM_PLATFORM_SOURCE_SHARED, + NM_PLATFORM_SOURCE_IP4LL, + NM_PLATFORM_SOURCE_PPP, + NM_PLATFORM_SOURCE_WWAN, + NM_PLATFORM_SOURCE_VPN, + NM_PLATFORM_SOURCE_DHCP, + NM_PLATFORM_SOURCE_RDISC, + NM_PLATFORM_SOURCE_USER, +} NMPlatformSource; + + +typedef struct { + __NMPlatformObject_COMMON; +} NMPlatformObject; + + +#define __NMPlatformIPAddress_COMMON \ + __NMPlatformObject_COMMON; \ + NMPlatformSource source; \ + \ + /* Timestamp in seconds in the reference system of nm_utils_get_monotonic_timestamp_*(). + * + * The rules are: + * 1 @lifetime==0: @timestamp and @preferred is irrelevant (but mostly set to 0 too). Such addresses + * are permanent. This rule is so that unset addresses (calloc) are permanent by default. + * 2 @lifetime==@preferred==NM_PLATFORM_LIFETIME_PERMANENT: @timestamp is irrelevant (but mostly + * set to 0). Such addresses are permanent. + * 3 Non permanent addreses should (almost) always have @timestamp > 0. 0 is not a valid timestamp + * and never returned by nm_utils_get_monotonic_timestamp_s(). In this case @valid/@preferred + * is anchored at @timestamp. + * 4 Non permanent addresses with @timestamp == 0 are implicitely anchored at *now*, thus the time + * moves as time goes by. This is usually not useful, except e.g. nm_platform_ip[46]_address_add(). + * + * Non permanent addresses from DHCP/RA might have the @timestamp set to the moment of when the + * lease was received. Addresses from kernel might have the @timestamp based on the last modification + * time of the addresses. But don't rely on this behaviour, the @timestamp is only defined for anchoring + * @lifetime and @preferred. + */ \ + guint32 timestamp; \ + guint32 lifetime; /* seconds since timestamp */ \ + guint32 preferred; /* seconds since timestamp */ \ + int plen; \ + ; + +/** + * NMPlatformIPAddress: + * + * Common parts of NMPlatformIP4Address and NMPlatformIP6Address. + **/ +typedef struct { + __NMPlatformIPAddress_COMMON; + union { + guint8 address_ptr[1]; + guint32 __dummy_for_32bit_alignment; + }; +} NMPlatformIPAddress; + +/** + * NMPlatformIP4Address: + * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_s() + **/ +typedef struct { + __NMPlatformIPAddress_COMMON; + in_addr_t address; + in_addr_t peer_address; /* PTP peer address */ + char label[IFNAMSIZ]; +} NMPlatformIP4Address; +G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_OFFSET (NMPlatformIP4Address, address)); + +/** + * NMPlatformIP6Address: + * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_s() + **/ +typedef struct { + __NMPlatformIPAddress_COMMON; + struct in6_addr address; + struct in6_addr peer_address; + guint flags; /* ifa_flags from <linux/if_addr.h>, field type "unsigned int" is as used in rtnl_addr_get_flags. */ +} NMPlatformIP6Address; +G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_OFFSET (NMPlatformIP6Address, address)); + +#undef __NMPlatformIPAddress_COMMON + + +#define NM_PLATFORM_ROUTE_METRIC_DEFAULT 1024 + +#define __NMPlatformIPRoute_COMMON \ + __NMPlatformObject_COMMON; \ + NMPlatformSource source; \ + int plen; \ + guint metric; \ + guint mss; \ + ; + +typedef struct { + __NMPlatformIPRoute_COMMON; + union { + guint8 network_ptr[1]; + guint32 __dummy_for_32bit_alignment; + }; +} NMPlatformIPRoute; + +typedef struct { + __NMPlatformIPRoute_COMMON; + in_addr_t network; + in_addr_t gateway; +} NMPlatformIP4Route; +G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OFFSET (NMPlatformIP4Route, network)); + +typedef struct { + __NMPlatformIPRoute_COMMON; + struct in6_addr network; + struct in6_addr gateway; +} NMPlatformIP6Route; +G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OFFSET (NMPlatformIP6Route, network)); + +#undef __NMPlatformIPRoute_COMMON + + +#undef __NMPlatformObject_COMMON + + +typedef struct { + int peer; +} NMPlatformVethProperties; + +typedef struct { + gint64 owner; + gint64 group; + const char *mode; + gboolean no_pi; + gboolean vnet_hdr; + gboolean multi_queue; +} NMPlatformTunProperties; + +typedef struct { + int parent_ifindex; + const char *mode; + gboolean no_promisc; +} NMPlatformMacvlanProperties; + +typedef struct { + int parent_ifindex; + guint32 id; + in_addr_t group; + in_addr_t local; + struct in6_addr group6; + struct in6_addr local6; + guint8 tos; + guint8 ttl; + gboolean learning; + guint32 ageing; + guint32 limit; + guint16 dst_port; + guint16 src_port_min; + guint16 src_port_max; + gboolean proxy; + gboolean rsc; + gboolean l2miss; + gboolean l3miss; +} NMPlatformVxlanProperties; + +typedef struct { + int parent_ifindex; + guint16 input_flags; + guint16 output_flags; + guint32 input_key; + guint32 output_key; + in_addr_t local; + in_addr_t remote; + guint8 ttl; + guint8 tos; + gboolean path_mtu_discovery; +} NMPlatformGreProperties; + +/******************************************************************/ + +/* NMPlatform abstract class and its implementations provide a layer between + * networkmanager's device management classes and the operating system kernel. + * + * How it works, is best seen in tests/nm-platform-test.c source file. + * + * NMPlatform provides interface to configure kernel interfaces and receive + * notifications about both internal and external configuration changes. It + * respects the following rules: + * + * 1) Every change made through NMPlatform is readily available and the respective + * signals are called synchronously. + * + * 2) State of an object retrieved from NMPlatform (through functions or events) + * is at least as recent than the state retrieved before. + * + * Any failure of the above rules should be fixed in NMPlatform implementations + * and tested in nm-platform-test. Synchronization hacks should never be put + * to any other code. That's why NMPlatform was created and that's why the + * testing code was written for it. + * + * In future, parts of linux platform implementation may be moved to the libnl + * library. + * + * If you have any problems related to NMPlatform on your system, you should + * always first run tests/nm-linux-platform-test as root and with all + * network configuration daemons stopped. Look at the code first. + */ + +typedef struct { + GObject parent; + + NMPlatformError error; +} NMPlatform; + +typedef struct { + GObjectClass parent; + + gboolean (*setup) (NMPlatform *); + + gboolean (*sysctl_set) (NMPlatform *, const char *path, const char *value); + char * (*sysctl_get) (NMPlatform *, const char *path); + + gboolean (*link_get) (NMPlatform *platform, int ifindex, NMPlatformLink *link); + GArray *(*link_get_all) (NMPlatform *); + gboolean (*link_add) (NMPlatform *, const char *name, NMLinkType type, const void *address, size_t address_len); + gboolean (*link_delete) (NMPlatform *, int ifindex); + int (*link_get_ifindex) (NMPlatform *, const char *name); + const char *(*link_get_name) (NMPlatform *, int ifindex); + NMLinkType (*link_get_type) (NMPlatform *, int ifindex); + const char *(*link_get_type_name) (NMPlatform *, int ifindex); + + gboolean (*link_refresh) (NMPlatform *, int ifindex); + + gboolean (*link_set_up) (NMPlatform *, int ifindex); + gboolean (*link_set_down) (NMPlatform *, int ifindex); + gboolean (*link_set_arp) (NMPlatform *, int ifindex); + gboolean (*link_set_noarp) (NMPlatform *, int ifindex); + gboolean (*link_is_up) (NMPlatform *, int ifindex); + gboolean (*link_is_connected) (NMPlatform *, int ifindex); + gboolean (*link_uses_arp) (NMPlatform *, int ifindex); + + gconstpointer (*link_get_address) (NMPlatform *, int ifindex, size_t *length); + gboolean (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length); + guint32 (*link_get_mtu) (NMPlatform *, int ifindex); + gboolean (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu); + + char * (*link_get_physical_port_id) (NMPlatform *, int ifindex); + gboolean (*link_get_wake_on_lan) (NMPlatform *, int ifindex); + + gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex); + gboolean (*link_supports_vlans) (NMPlatform *, int ifindex); + + gboolean (*link_enslave) (NMPlatform *, int master, int slave); + gboolean (*link_release) (NMPlatform *, int master, int slave); + gboolean (*link_get_master) (NMPlatform *, int slave); + gboolean (*master_set_option) (NMPlatform *, int ifindex, const char *option, const char *value); + char * (*master_get_option) (NMPlatform *, int ifindex, const char *option); + gboolean (*slave_set_option) (NMPlatform *, int ifindex, const char *option, const char *value); + char * (*slave_get_option) (NMPlatform *, int ifindex, const char *option); + + gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags); + gboolean (*vlan_get_info) (NMPlatform *, int ifindex, int *parent, int *vlan_id); + gboolean (*vlan_set_ingress_map) (NMPlatform *, int ifindex, int from, int to); + gboolean (*vlan_set_egress_map) (NMPlatform *, int ifindex, int from, int to); + + gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key); + + gboolean (*veth_get_properties) (NMPlatform *, int ifindex, NMPlatformVethProperties *properties); + gboolean (*tun_get_properties) (NMPlatform *, int ifindex, NMPlatformTunProperties *properties); + gboolean (*macvlan_get_properties) (NMPlatform *, int ifindex, NMPlatformMacvlanProperties *props); + gboolean (*vxlan_get_properties) (NMPlatform *, int ifindex, NMPlatformVxlanProperties *props); + gboolean (*gre_get_properties) (NMPlatform *, int ifindex, NMPlatformGreProperties *props); + + gboolean (*wifi_get_capabilities) (NMPlatform *, int ifindex, NMDeviceWifiCapabilities *caps); + gboolean (*wifi_get_bssid) (NMPlatform *, int ifindex, struct ether_addr *bssid); + GByteArray *(*wifi_get_ssid) (NMPlatform *, int ifindex); + guint32 (*wifi_get_frequency) (NMPlatform *, int ifindex); + int (*wifi_get_quality) (NMPlatform *, int ifindex); + guint32 (*wifi_get_rate) (NMPlatform *, int ifindex); + NM80211Mode (*wifi_get_mode) (NMPlatform *, int ifindex); + void (*wifi_set_mode) (NMPlatform *, int ifindex, NM80211Mode mode); + guint32 (*wifi_find_frequency) (NMPlatform *, int ifindex, const guint32 *freqs); + void (*wifi_indicate_addressing_running) (NMPlatform *, int ifindex, gboolean running); + + guint32 (*mesh_get_channel) (NMPlatform *, int ifindex); + gboolean (*mesh_set_channel) (NMPlatform *, int ifindex, guint32 channel); + gboolean (*mesh_set_ssid) (NMPlatform *, int ifindex, const GByteArray *ssid); + + GArray * (*ip4_address_get_all) (NMPlatform *, int ifindex); + GArray * (*ip6_address_get_all) (NMPlatform *, int ifindex); + gboolean (*ip4_address_add) (NMPlatform *, int ifindex, + in_addr_t address, in_addr_t peer_address, int plen, + guint32 lifetime, guint32 preferred_lft, + const char *label); + gboolean (*ip6_address_add) (NMPlatform *, int ifindex, + struct in6_addr address, struct in6_addr peer_address, int plen, + guint32 lifetime, guint32 preferred_lft, guint flags); + gboolean (*ip4_address_delete) (NMPlatform *, int ifindex, in_addr_t address, int plen); + gboolean (*ip6_address_delete) (NMPlatform *, int ifindex, struct in6_addr address, int plen); + gboolean (*ip4_address_exists) (NMPlatform *, int ifindex, in_addr_t address, int plen); + gboolean (*ip6_address_exists) (NMPlatform *, int ifindex, struct in6_addr address, int plen); + + GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, gboolean include_default); + GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex, gboolean include_default); + gboolean (*ip4_route_add) (NMPlatform *, int ifindex, NMPlatformSource source, + in_addr_t network, int plen, in_addr_t gateway, + int prio, int mss); + gboolean (*ip6_route_add) (NMPlatform *, int ifindex, NMPlatformSource source, + struct in6_addr network, int plen, struct in6_addr gateway, + int prio, int mss); + gboolean (*ip4_route_delete) (NMPlatform *, int ifindex, in_addr_t network, int plen, int metric); + gboolean (*ip6_route_delete) (NMPlatform *, int ifindex, struct in6_addr network, int plen, int metric); + gboolean (*ip4_route_exists) (NMPlatform *, int ifindex, in_addr_t network, int plen, int metric); + gboolean (*ip6_route_exists) (NMPlatform *, int ifindex, struct in6_addr network, int plen, int metric); + + gboolean (*check_support_kernel_extended_ifa_flags) (NMPlatform *); +} NMPlatformClass; + +/* NMPlatform signals + * + * Each signal handler is called with a type-specific object that provides + * key attributes that constitute identity of the object. They may also + * provide additional attributes for convenience. + * + * The object only intended to be used by the signal handler to determine + * the current values. It is no longer valid after the signal handler exits + * but you are free to copy the provided information and use it for later + * reference. + */ +#define NM_PLATFORM_SIGNAL_LINK_CHANGED "link-changed" +#define NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED "ip4-address-changed" +#define NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED "ip6-address-changed" +#define NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED "ip4-route-changed" +#define NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED "ip6-route-changed" + +/******************************************************************/ + +GType nm_platform_get_type (void); + +void nm_platform_setup (GType type); +NMPlatform *nm_platform_get (void); +void nm_platform_free (void); + +/******************************************************************/ + +void nm_platform_set_error (NMPlatformError error); +NMPlatformError nm_platform_get_error (void); +const char *nm_platform_get_error_msg (void); + +void nm_platform_query_devices (void); + +gboolean nm_platform_sysctl_set (const char *path, const char *value); +char *nm_platform_sysctl_get (const char *path); +gint32 nm_platform_sysctl_get_int32 (const char *path, gint32 fallback); +gint64 nm_platform_sysctl_get_int_checked (const char *path, guint base, gint64 min, gint64 max, gint64 fallback); + +gboolean nm_platform_link_get (int ifindex, NMPlatformLink *link); +GArray *nm_platform_link_get_all (void); +gboolean nm_platform_dummy_add (const char *name); +gboolean nm_platform_bridge_add (const char *name, const void *address, size_t address_len); +gboolean nm_platform_bond_add (const char *name); +gboolean nm_platform_team_add (const char *name); +gboolean nm_platform_link_exists (const char *name); +gboolean nm_platform_link_delete (int ifindex); +int nm_platform_link_get_ifindex (const char *name); +const char *nm_platform_link_get_name (int ifindex); +NMLinkType nm_platform_link_get_type (int ifindex); +const char *nm_platform_link_get_type_name (int ifindex); +gboolean nm_platform_link_is_software (int ifindex); +gboolean nm_platform_link_supports_slaves (int ifindex); + +gboolean nm_platform_link_refresh (int ifindex); + +gboolean nm_platform_link_set_up (int ifindex); +gboolean nm_platform_link_set_down (int ifindex); +gboolean nm_platform_link_set_arp (int ifindex); +gboolean nm_platform_link_set_noarp (int ifindex); +gboolean nm_platform_link_is_up (int ifindex); +gboolean nm_platform_link_is_connected (int ifindex); +gboolean nm_platform_link_uses_arp (int ifindex); + +gconstpointer nm_platform_link_get_address (int ifindex, size_t *length); +gboolean nm_platform_link_set_address (int ifindex, const void *address, size_t length); +guint32 nm_platform_link_get_mtu (int ifindex); +gboolean nm_platform_link_set_mtu (int ifindex, guint32 mtu); + +char *nm_platform_link_get_physical_port_id (int ifindex); +gboolean nm_platform_link_get_wake_on_lan (int ifindex); + +gboolean nm_platform_link_supports_carrier_detect (int ifindex); +gboolean nm_platform_link_supports_vlans (int ifindex); + +gboolean nm_platform_link_enslave (int master, int slave); +gboolean nm_platform_link_release (int master, int slave); +int nm_platform_link_get_master (int slave); +gboolean nm_platform_master_set_option (int ifindex, const char *option, const char *value); +char *nm_platform_master_get_option (int ifindex, const char *option); +gboolean nm_platform_slave_set_option (int ifindex, const char *option, const char *value); +char *nm_platform_slave_get_option (int ifindex, const char *option); + +gboolean nm_platform_vlan_add (const char *name, int parent, int vlanid, guint32 vlanflags); +gboolean nm_platform_vlan_get_info (int ifindex, int *parent, int *vlanid); +gboolean nm_platform_vlan_set_ingress_map (int ifindex, int from, int to); +gboolean nm_platform_vlan_set_egress_map (int ifindex, int from, int to); + +gboolean nm_platform_infiniband_partition_add (int parent, int p_key); + +gboolean nm_platform_veth_get_properties (int ifindex, NMPlatformVethProperties *properties); +gboolean nm_platform_tun_get_properties (int ifindex, NMPlatformTunProperties *properties); +gboolean nm_platform_macvlan_get_properties (int ifindex, NMPlatformMacvlanProperties *props); +gboolean nm_platform_vxlan_get_properties (int ifindex, NMPlatformVxlanProperties *props); +gboolean nm_platform_gre_get_properties (int ifindex, NMPlatformGreProperties *props); + +gboolean nm_platform_wifi_get_capabilities (int ifindex, NMDeviceWifiCapabilities *caps); +gboolean nm_platform_wifi_get_bssid (int ifindex, struct ether_addr *bssid); +GByteArray *nm_platform_wifi_get_ssid (int ifindex); +guint32 nm_platform_wifi_get_frequency (int ifindex); +int nm_platform_wifi_get_quality (int ifindex); +guint32 nm_platform_wifi_get_rate (int ifindex); +NM80211Mode nm_platform_wifi_get_mode (int ifindex); +void nm_platform_wifi_set_mode (int ifindex, NM80211Mode mode); +guint32 nm_platform_wifi_find_frequency (int ifindex, const guint32 *freqs); +void nm_platform_wifi_indicate_addressing_running (int ifindex, gboolean running); + +guint32 nm_platform_mesh_get_channel (int ifindex); +gboolean nm_platform_mesh_set_channel (int ifindex, guint32 channel); +gboolean nm_platform_mesh_set_ssid (int ifindex, const GByteArray *ssid); + +GArray *nm_platform_ip4_address_get_all (int ifindex); +GArray *nm_platform_ip6_address_get_all (int ifindex); +gboolean nm_platform_ip4_address_add (int ifindex, + in_addr_t address, in_addr_t peer_address, int plen, + guint32 lifetime, guint32 preferred_lft, + const char *label); +gboolean nm_platform_ip6_address_add (int ifindex, + struct in6_addr address, struct in6_addr peer_address, int plen, + guint32 lifetime, guint32 preferred_lft, guint flags); +gboolean nm_platform_ip4_address_delete (int ifindex, in_addr_t address, int plen); +gboolean nm_platform_ip6_address_delete (int ifindex, struct in6_addr address, int plen); +gboolean nm_platform_ip4_address_exists (int ifindex, in_addr_t address, int plen); +gboolean nm_platform_ip6_address_exists (int ifindex, struct in6_addr address, int plen); +gboolean nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses); +gboolean nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses); +gboolean nm_platform_address_flush (int ifindex); + +GArray *nm_platform_ip4_route_get_all (int ifindex, gboolean include_default); +GArray *nm_platform_ip6_route_get_all (int ifindex, gboolean include_default); +gboolean nm_platform_route_set_metric (int ifindex, int metric); +gboolean nm_platform_ip4_route_add (int ifindex, NMPlatformSource source, + in_addr_t network, int plen, in_addr_t gateway, + int metric, int mss); +gboolean nm_platform_ip6_route_add (int ifindex, NMPlatformSource source, + struct in6_addr network, int plen, struct in6_addr gateway, + int metric, int mss); +gboolean nm_platform_ip4_route_delete (int ifindex, in_addr_t network, int plen, int metric); +gboolean nm_platform_ip6_route_delete (int ifindex, struct in6_addr network, int plen, int metric); +gboolean nm_platform_ip4_route_exists (int ifindex, in_addr_t network, int plen, int metric); +gboolean nm_platform_ip6_route_exists (int ifindex, struct in6_addr network, int plen, int metric); +gboolean nm_platform_ip4_route_sync (int ifindex, const GArray *known_routes); +gboolean nm_platform_ip6_route_sync (int ifindex, const GArray *known_routes); +gboolean nm_platform_route_flush (int ifindex); + +const char *nm_platform_link_to_string (const NMPlatformLink *link); +const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address); +const char *nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address); +const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route); +const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route); + +int nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b); +int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b); +int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b); +int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b); +int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b); + +gboolean nm_platform_check_support_libnl_extended_ifa_flags (void); +gboolean nm_platform_check_support_kernel_extended_ifa_flags (void); + +void nm_platform_addr_flags2str (int flags, char *buf, size_t size); + +int nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatformIPAddress *b); + +#define auto_g_free __attribute__((cleanup(put_g_free))) +static void __attribute__((unused)) +put_g_free (void *ptr) +{ + g_clear_pointer ((gpointer *) ptr, g_free); +} + +#endif /* NM_PLATFORM_H */ diff --git a/src/platform/tests/Makefile.am b/src/platform/tests/Makefile.am new file mode 100644 index 00000000..9b10ea7b --- /dev/null +++ b/src/platform/tests/Makefile.am @@ -0,0 +1,116 @@ +AM_CPPFLAGS = \ + -I${top_srcdir} \ + -I${top_srcdir}/include \ + -I${top_builddir}/include \ + -I${top_srcdir}/src \ + -I${top_builddir}/src \ + -I${top_srcdir}/src/logging \ + -I${top_srcdir}/libnm-util \ + -I${top_builddir}/libnm-util \ + -I${srcdir}/.. \ + -DG_LOG_DOMAIN=\""NetworkManager"\" \ + -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ + $(GLIB_CFLAGS) \ + $(GUDEV_CFLAGS) \ + $(LIBNL_CFLAGS) + +if REQUIRE_ROOT_TESTS +AM_CPPFLAGS += -DREQUIRE_ROOT_TESTS=1 +endif + +PLATFORM_SOURCES = \ + ../nm-platform.c \ + ../nm-fake-platform.c \ + ../nm-linux-platform.c +TEST_SOURCES = $(PLATFORM_SOURCES) test-common.c test-common.h +AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) +AM_LDFLAGS = $(GLIB_LIBS) $(GUDEV_LIBS) $(LIBNL_LIBS) $(CODE_COVERAGE_LDFLAGS) +PLATFORM_LDADD = \ + $(top_builddir)/src/libNetworkManager.la + +@GNOME_CODE_COVERAGE_RULES@ + +noinst_PROGRAMS = \ + dump \ + monitor \ + platform \ + test-link-fake \ + test-link-linux \ + test-address-fake \ + test-address-linux \ + test-route-fake \ + test-route-linux \ + test-cleanup-fake \ + test-cleanup-linux + +EXTRA_DIST = test-common.h + +monitor_SOURCES = monitor.c $(PLATFORM_SOURCES) +monitor_LDADD = $(PLATFORM_LDADD) + +dump_SOURCES = dump.c $(PLATFORM_SOURCES) +dump_LDADD = $(PLATFORM_LDADD) + +platform_SOURCES = platform.c $(PLATFORM_SOURCES) +platform_LDADD = $(PLATFORM_LDADD) + +test_link_fake_SOURCES = test-link.c $(TEST_SOURCES) +test_link_fake_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_fake_platform_setup \ + -DKERNEL_HACKS=0 +test_link_fake_LDADD = $(PLATFORM_LDADD) + +test_link_linux_SOURCES = test-link.c $(TEST_SOURCES) +test_link_linux_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_linux_platform_setup \ + -DKERNEL_HACKS=1 +test_link_linux_LDADD = $(PLATFORM_LDADD) + +test_address_fake_SOURCES = test-address.c $(TEST_SOURCES) +test_address_fake_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_fake_platform_setup \ + -DKERNEL_HACKS=0 +test_address_fake_LDADD = $(PLATFORM_LDADD) + +test_address_linux_SOURCES = test-address.c $(TEST_SOURCES) +test_address_linux_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_linux_platform_setup \ + -DKERNEL_HACKS=1 +test_address_linux_LDADD = $(PLATFORM_LDADD) + +test_route_fake_SOURCES = test-route.c $(TEST_SOURCES) +test_route_fake_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_fake_platform_setup \ + -DKERNEL_HACKS=0 +test_route_fake_LDADD = $(PLATFORM_LDADD) + +test_route_linux_SOURCES = test-route.c $(TEST_SOURCES) +test_route_linux_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_linux_platform_setup \ + -DKERNEL_HACKS=1 +test_route_linux_LDADD = $(PLATFORM_LDADD) + +test_cleanup_fake_SOURCES = test-cleanup.c $(TEST_SOURCES) +test_cleanup_fake_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_fake_platform_setup \ + -DKERNEL_HACKS=0 +test_cleanup_fake_LDADD = $(PLATFORM_LDADD) + +test_cleanup_linux_SOURCES = test-cleanup.c $(TEST_SOURCES) +test_cleanup_linux_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_linux_platform_setup \ + -DKERNEL_HACKS=1 +test_cleanup_linux_LDADD = $(PLATFORM_LDADD) + +#@VALGRIND_RULES@ +TESTS = test-link-fake test-address-fake test-route-fake test-cleanup-fake test-link-linux test-address-linux test-route-linux test-cleanup-linux + + diff --git a/src/platform/tests/Makefile.in b/src/platform/tests/Makefile.in new file mode 100644 index 00000000..6b03e315 --- /dev/null +++ b/src/platform/tests/Makefile.in @@ -0,0 +1,1702 @@ +# 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@ +@REQUIRE_ROOT_TESTS_TRUE@am__append_1 = -DREQUIRE_ROOT_TESTS=1 +noinst_PROGRAMS = dump$(EXEEXT) monitor$(EXEEXT) platform$(EXEEXT) \ + test-link-fake$(EXEEXT) test-link-linux$(EXEEXT) \ + test-address-fake$(EXEEXT) test-address-linux$(EXEEXT) \ + test-route-fake$(EXEEXT) test-route-linux$(EXEEXT) \ + test-cleanup-fake$(EXEEXT) test-cleanup-linux$(EXEEXT) +TESTS = test-link-fake$(EXEEXT) test-address-fake$(EXEEXT) \ + test-route-fake$(EXEEXT) test-cleanup-fake$(EXEEXT) \ + test-link-linux$(EXEEXT) test-address-linux$(EXEEXT) \ + test-route-linux$(EXEEXT) test-cleanup-linux$(EXEEXT) +subdir = src/platform/tests +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 = +PROGRAMS = $(noinst_PROGRAMS) +am__objects_1 = nm-platform.$(OBJEXT) nm-fake-platform.$(OBJEXT) \ + nm-linux-platform.$(OBJEXT) +am_dump_OBJECTS = dump.$(OBJEXT) $(am__objects_1) +dump_OBJECTS = $(am_dump_OBJECTS) +dump_DEPENDENCIES = $(PLATFORM_LDADD) +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 = +am_monitor_OBJECTS = monitor.$(OBJEXT) $(am__objects_1) +monitor_OBJECTS = $(am_monitor_OBJECTS) +monitor_DEPENDENCIES = $(PLATFORM_LDADD) +am_platform_OBJECTS = platform.$(OBJEXT) $(am__objects_1) +platform_OBJECTS = $(am_platform_OBJECTS) +platform_DEPENDENCIES = $(PLATFORM_LDADD) +am__objects_2 = test_address_fake-nm-platform.$(OBJEXT) \ + test_address_fake-nm-fake-platform.$(OBJEXT) \ + test_address_fake-nm-linux-platform.$(OBJEXT) +am__objects_3 = $(am__objects_2) \ + test_address_fake-test-common.$(OBJEXT) +am_test_address_fake_OBJECTS = \ + test_address_fake-test-address.$(OBJEXT) $(am__objects_3) +test_address_fake_OBJECTS = $(am_test_address_fake_OBJECTS) +test_address_fake_DEPENDENCIES = $(PLATFORM_LDADD) +am__objects_4 = test_address_linux-nm-platform.$(OBJEXT) \ + test_address_linux-nm-fake-platform.$(OBJEXT) \ + test_address_linux-nm-linux-platform.$(OBJEXT) +am__objects_5 = $(am__objects_4) \ + test_address_linux-test-common.$(OBJEXT) +am_test_address_linux_OBJECTS = \ + test_address_linux-test-address.$(OBJEXT) $(am__objects_5) +test_address_linux_OBJECTS = $(am_test_address_linux_OBJECTS) +test_address_linux_DEPENDENCIES = $(PLATFORM_LDADD) +am__objects_6 = test_cleanup_fake-nm-platform.$(OBJEXT) \ + test_cleanup_fake-nm-fake-platform.$(OBJEXT) \ + test_cleanup_fake-nm-linux-platform.$(OBJEXT) +am__objects_7 = $(am__objects_6) \ + test_cleanup_fake-test-common.$(OBJEXT) +am_test_cleanup_fake_OBJECTS = \ + test_cleanup_fake-test-cleanup.$(OBJEXT) $(am__objects_7) +test_cleanup_fake_OBJECTS = $(am_test_cleanup_fake_OBJECTS) +test_cleanup_fake_DEPENDENCIES = $(PLATFORM_LDADD) +am__objects_8 = test_cleanup_linux-nm-platform.$(OBJEXT) \ + test_cleanup_linux-nm-fake-platform.$(OBJEXT) \ + test_cleanup_linux-nm-linux-platform.$(OBJEXT) +am__objects_9 = $(am__objects_8) \ + test_cleanup_linux-test-common.$(OBJEXT) +am_test_cleanup_linux_OBJECTS = \ + test_cleanup_linux-test-cleanup.$(OBJEXT) $(am__objects_9) +test_cleanup_linux_OBJECTS = $(am_test_cleanup_linux_OBJECTS) +test_cleanup_linux_DEPENDENCIES = $(PLATFORM_LDADD) +am__objects_10 = test_link_fake-nm-platform.$(OBJEXT) \ + test_link_fake-nm-fake-platform.$(OBJEXT) \ + test_link_fake-nm-linux-platform.$(OBJEXT) +am__objects_11 = $(am__objects_10) \ + test_link_fake-test-common.$(OBJEXT) +am_test_link_fake_OBJECTS = test_link_fake-test-link.$(OBJEXT) \ + $(am__objects_11) +test_link_fake_OBJECTS = $(am_test_link_fake_OBJECTS) +test_link_fake_DEPENDENCIES = $(PLATFORM_LDADD) +am__objects_12 = test_link_linux-nm-platform.$(OBJEXT) \ + test_link_linux-nm-fake-platform.$(OBJEXT) \ + test_link_linux-nm-linux-platform.$(OBJEXT) +am__objects_13 = $(am__objects_12) \ + test_link_linux-test-common.$(OBJEXT) +am_test_link_linux_OBJECTS = test_link_linux-test-link.$(OBJEXT) \ + $(am__objects_13) +test_link_linux_OBJECTS = $(am_test_link_linux_OBJECTS) +test_link_linux_DEPENDENCIES = $(PLATFORM_LDADD) +am__objects_14 = test_route_fake-nm-platform.$(OBJEXT) \ + test_route_fake-nm-fake-platform.$(OBJEXT) \ + test_route_fake-nm-linux-platform.$(OBJEXT) +am__objects_15 = $(am__objects_14) \ + test_route_fake-test-common.$(OBJEXT) +am_test_route_fake_OBJECTS = test_route_fake-test-route.$(OBJEXT) \ + $(am__objects_15) +test_route_fake_OBJECTS = $(am_test_route_fake_OBJECTS) +test_route_fake_DEPENDENCIES = $(PLATFORM_LDADD) +am__objects_16 = test_route_linux-nm-platform.$(OBJEXT) \ + test_route_linux-nm-fake-platform.$(OBJEXT) \ + test_route_linux-nm-linux-platform.$(OBJEXT) +am__objects_17 = $(am__objects_16) \ + test_route_linux-test-common.$(OBJEXT) +am_test_route_linux_OBJECTS = test_route_linux-test-route.$(OBJEXT) \ + $(am__objects_17) +test_route_linux_OBJECTS = $(am_test_route_linux_OBJECTS) +test_route_linux_DEPENDENCIES = $(PLATFORM_LDADD) +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 = $(dump_SOURCES) $(monitor_SOURCES) $(platform_SOURCES) \ + $(test_address_fake_SOURCES) $(test_address_linux_SOURCES) \ + $(test_cleanup_fake_SOURCES) $(test_cleanup_linux_SOURCES) \ + $(test_link_fake_SOURCES) $(test_link_linux_SOURCES) \ + $(test_route_fake_SOURCES) $(test_route_linux_SOURCES) +DIST_SOURCES = $(dump_SOURCES) $(monitor_SOURCES) $(platform_SOURCES) \ + $(test_address_fake_SOURCES) $(test_address_linux_SOURCES) \ + $(test_cleanup_fake_SOURCES) $(test_cleanup_linux_SOURCES) \ + $(test_link_fake_SOURCES) $(test_link_linux_SOURCES) \ + $(test_route_fake_SOURCES) $(test_route_linux_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 +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red='[0;31m'; \ + grn='[0;32m'; \ + lgn='[1;32m'; \ + blu='[1;34m'; \ + mgn='[0;35m'; \ + brg='[1m'; \ + std='[m'; \ + fi; \ +} +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} -I${top_srcdir}/include \ + -I${top_builddir}/include -I${top_srcdir}/src \ + -I${top_builddir}/src -I${top_srcdir}/src/logging \ + -I${top_srcdir}/libnm-util -I${top_builddir}/libnm-util \ + -I${srcdir}/.. -DG_LOG_DOMAIN=\""NetworkManager"\" \ + -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE $(GLIB_CFLAGS) \ + $(GUDEV_CFLAGS) $(LIBNL_CFLAGS) $(am__append_1) +PLATFORM_SOURCES = \ + ../nm-platform.c \ + ../nm-fake-platform.c \ + ../nm-linux-platform.c + +TEST_SOURCES = $(PLATFORM_SOURCES) test-common.c test-common.h +AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) +AM_LDFLAGS = $(GLIB_LIBS) $(GUDEV_LIBS) $(LIBNL_LIBS) $(CODE_COVERAGE_LDFLAGS) +PLATFORM_LDADD = \ + $(top_builddir)/src/libNetworkManager.la + +EXTRA_DIST = test-common.h +monitor_SOURCES = monitor.c $(PLATFORM_SOURCES) +monitor_LDADD = $(PLATFORM_LDADD) +dump_SOURCES = dump.c $(PLATFORM_SOURCES) +dump_LDADD = $(PLATFORM_LDADD) +platform_SOURCES = platform.c $(PLATFORM_SOURCES) +platform_LDADD = $(PLATFORM_LDADD) +test_link_fake_SOURCES = test-link.c $(TEST_SOURCES) +test_link_fake_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_fake_platform_setup \ + -DKERNEL_HACKS=0 + +test_link_fake_LDADD = $(PLATFORM_LDADD) +test_link_linux_SOURCES = test-link.c $(TEST_SOURCES) +test_link_linux_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_linux_platform_setup \ + -DKERNEL_HACKS=1 + +test_link_linux_LDADD = $(PLATFORM_LDADD) +test_address_fake_SOURCES = test-address.c $(TEST_SOURCES) +test_address_fake_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_fake_platform_setup \ + -DKERNEL_HACKS=0 + +test_address_fake_LDADD = $(PLATFORM_LDADD) +test_address_linux_SOURCES = test-address.c $(TEST_SOURCES) +test_address_linux_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_linux_platform_setup \ + -DKERNEL_HACKS=1 + +test_address_linux_LDADD = $(PLATFORM_LDADD) +test_route_fake_SOURCES = test-route.c $(TEST_SOURCES) +test_route_fake_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_fake_platform_setup \ + -DKERNEL_HACKS=0 + +test_route_fake_LDADD = $(PLATFORM_LDADD) +test_route_linux_SOURCES = test-route.c $(TEST_SOURCES) +test_route_linux_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_linux_platform_setup \ + -DKERNEL_HACKS=1 + +test_route_linux_LDADD = $(PLATFORM_LDADD) +test_cleanup_fake_SOURCES = test-cleanup.c $(TEST_SOURCES) +test_cleanup_fake_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_fake_platform_setup \ + -DKERNEL_HACKS=0 + +test_cleanup_fake_LDADD = $(PLATFORM_LDADD) +test_cleanup_linux_SOURCES = test-cleanup.c $(TEST_SOURCES) +test_cleanup_linux_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DSETUP=nm_linux_platform_setup \ + -DKERNEL_HACKS=1 + +test_cleanup_linux_LDADD = $(PLATFORM_LDADD) +all: 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/platform/tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/platform/tests/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): + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +dump$(EXEEXT): $(dump_OBJECTS) $(dump_DEPENDENCIES) $(EXTRA_dump_DEPENDENCIES) + @rm -f dump$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(dump_OBJECTS) $(dump_LDADD) $(LIBS) + +monitor$(EXEEXT): $(monitor_OBJECTS) $(monitor_DEPENDENCIES) $(EXTRA_monitor_DEPENDENCIES) + @rm -f monitor$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(monitor_OBJECTS) $(monitor_LDADD) $(LIBS) + +platform$(EXEEXT): $(platform_OBJECTS) $(platform_DEPENDENCIES) $(EXTRA_platform_DEPENDENCIES) + @rm -f platform$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(platform_OBJECTS) $(platform_LDADD) $(LIBS) + +test-address-fake$(EXEEXT): $(test_address_fake_OBJECTS) $(test_address_fake_DEPENDENCIES) $(EXTRA_test_address_fake_DEPENDENCIES) + @rm -f test-address-fake$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_address_fake_OBJECTS) $(test_address_fake_LDADD) $(LIBS) + +test-address-linux$(EXEEXT): $(test_address_linux_OBJECTS) $(test_address_linux_DEPENDENCIES) $(EXTRA_test_address_linux_DEPENDENCIES) + @rm -f test-address-linux$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_address_linux_OBJECTS) $(test_address_linux_LDADD) $(LIBS) + +test-cleanup-fake$(EXEEXT): $(test_cleanup_fake_OBJECTS) $(test_cleanup_fake_DEPENDENCIES) $(EXTRA_test_cleanup_fake_DEPENDENCIES) + @rm -f test-cleanup-fake$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_cleanup_fake_OBJECTS) $(test_cleanup_fake_LDADD) $(LIBS) + +test-cleanup-linux$(EXEEXT): $(test_cleanup_linux_OBJECTS) $(test_cleanup_linux_DEPENDENCIES) $(EXTRA_test_cleanup_linux_DEPENDENCIES) + @rm -f test-cleanup-linux$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_cleanup_linux_OBJECTS) $(test_cleanup_linux_LDADD) $(LIBS) + +test-link-fake$(EXEEXT): $(test_link_fake_OBJECTS) $(test_link_fake_DEPENDENCIES) $(EXTRA_test_link_fake_DEPENDENCIES) + @rm -f test-link-fake$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_link_fake_OBJECTS) $(test_link_fake_LDADD) $(LIBS) + +test-link-linux$(EXEEXT): $(test_link_linux_OBJECTS) $(test_link_linux_DEPENDENCIES) $(EXTRA_test_link_linux_DEPENDENCIES) + @rm -f test-link-linux$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_link_linux_OBJECTS) $(test_link_linux_LDADD) $(LIBS) + +test-route-fake$(EXEEXT): $(test_route_fake_OBJECTS) $(test_route_fake_DEPENDENCIES) $(EXTRA_test_route_fake_DEPENDENCIES) + @rm -f test-route-fake$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_route_fake_OBJECTS) $(test_route_fake_LDADD) $(LIBS) + +test-route-linux$(EXEEXT): $(test_route_linux_OBJECTS) $(test_route_linux_DEPENDENCIES) $(EXTRA_test_route_linux_DEPENDENCIES) + @rm -f test-route-linux$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_route_linux_OBJECTS) $(test_route_linux_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/monitor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-fake-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-linux-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_address_fake-nm-fake-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_address_fake-nm-linux-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_address_fake-nm-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_address_fake-test-address.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_address_fake-test-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_address_linux-nm-fake-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_address_linux-nm-linux-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_address_linux-nm-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_address_linux-test-address.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_address_linux-test-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_cleanup_fake-nm-fake-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_cleanup_fake-nm-linux-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_cleanup_fake-nm-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_cleanup_fake-test-cleanup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_cleanup_fake-test-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_cleanup_linux-nm-fake-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_cleanup_linux-nm-linux-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_cleanup_linux-nm-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_cleanup_linux-test-cleanup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_cleanup_linux-test-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_link_fake-nm-fake-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_link_fake-nm-linux-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_link_fake-nm-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_link_fake-test-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_link_fake-test-link.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_link_linux-nm-fake-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_link_linux-nm-linux-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_link_linux-nm-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_link_linux-test-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_link_linux-test-link.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_route_fake-nm-fake-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_route_fake-nm-linux-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_route_fake-nm-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_route_fake-test-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_route_fake-test-route.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_route_linux-nm-fake-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_route_linux-nm-linux-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_route_linux-nm-platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_route_linux-test-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_route_linux-test-route.Po@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 $@ $< + +nm-platform.o: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-platform.o -MD -MP -MF $(DEPDIR)/nm-platform.Tpo -c -o nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-platform.Tpo $(DEPDIR)/nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='nm-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c + +nm-platform.obj: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-platform.obj -MD -MP -MF $(DEPDIR)/nm-platform.Tpo -c -o nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-platform.Tpo $(DEPDIR)/nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='nm-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` + +nm-fake-platform.o: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-fake-platform.o -MD -MP -MF $(DEPDIR)/nm-fake-platform.Tpo -c -o nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-fake-platform.Tpo $(DEPDIR)/nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='nm-fake-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c + +nm-fake-platform.obj: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-fake-platform.obj -MD -MP -MF $(DEPDIR)/nm-fake-platform.Tpo -c -o nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-fake-platform.Tpo $(DEPDIR)/nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='nm-fake-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` + +nm-linux-platform.o: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-linux-platform.o -MD -MP -MF $(DEPDIR)/nm-linux-platform.Tpo -c -o nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-linux-platform.Tpo $(DEPDIR)/nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='nm-linux-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c + +nm-linux-platform.obj: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-linux-platform.obj -MD -MP -MF $(DEPDIR)/nm-linux-platform.Tpo -c -o nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-linux-platform.Tpo $(DEPDIR)/nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='nm-linux-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` + +test_address_fake-test-address.o: test-address.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_fake-test-address.o -MD -MP -MF $(DEPDIR)/test_address_fake-test-address.Tpo -c -o test_address_fake-test-address.o `test -f 'test-address.c' || echo '$(srcdir)/'`test-address.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_fake-test-address.Tpo $(DEPDIR)/test_address_fake-test-address.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-address.c' object='test_address_fake-test-address.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_fake-test-address.o `test -f 'test-address.c' || echo '$(srcdir)/'`test-address.c + +test_address_fake-test-address.obj: test-address.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_fake-test-address.obj -MD -MP -MF $(DEPDIR)/test_address_fake-test-address.Tpo -c -o test_address_fake-test-address.obj `if test -f 'test-address.c'; then $(CYGPATH_W) 'test-address.c'; else $(CYGPATH_W) '$(srcdir)/test-address.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_fake-test-address.Tpo $(DEPDIR)/test_address_fake-test-address.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-address.c' object='test_address_fake-test-address.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_fake-test-address.obj `if test -f 'test-address.c'; then $(CYGPATH_W) 'test-address.c'; else $(CYGPATH_W) '$(srcdir)/test-address.c'; fi` + +test_address_fake-nm-platform.o: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_fake-nm-platform.o -MD -MP -MF $(DEPDIR)/test_address_fake-nm-platform.Tpo -c -o test_address_fake-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_fake-nm-platform.Tpo $(DEPDIR)/test_address_fake-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_address_fake-nm-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_fake-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c + +test_address_fake-nm-platform.obj: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_fake-nm-platform.obj -MD -MP -MF $(DEPDIR)/test_address_fake-nm-platform.Tpo -c -o test_address_fake-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_fake-nm-platform.Tpo $(DEPDIR)/test_address_fake-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_address_fake-nm-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_fake-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` + +test_address_fake-nm-fake-platform.o: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_fake-nm-fake-platform.o -MD -MP -MF $(DEPDIR)/test_address_fake-nm-fake-platform.Tpo -c -o test_address_fake-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_fake-nm-fake-platform.Tpo $(DEPDIR)/test_address_fake-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_address_fake-nm-fake-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_fake-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c + +test_address_fake-nm-fake-platform.obj: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_fake-nm-fake-platform.obj -MD -MP -MF $(DEPDIR)/test_address_fake-nm-fake-platform.Tpo -c -o test_address_fake-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_fake-nm-fake-platform.Tpo $(DEPDIR)/test_address_fake-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_address_fake-nm-fake-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_fake-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` + +test_address_fake-nm-linux-platform.o: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_fake-nm-linux-platform.o -MD -MP -MF $(DEPDIR)/test_address_fake-nm-linux-platform.Tpo -c -o test_address_fake-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_fake-nm-linux-platform.Tpo $(DEPDIR)/test_address_fake-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_address_fake-nm-linux-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_fake-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c + +test_address_fake-nm-linux-platform.obj: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_fake-nm-linux-platform.obj -MD -MP -MF $(DEPDIR)/test_address_fake-nm-linux-platform.Tpo -c -o test_address_fake-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_fake-nm-linux-platform.Tpo $(DEPDIR)/test_address_fake-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_address_fake-nm-linux-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_fake-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` + +test_address_fake-test-common.o: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_fake-test-common.o -MD -MP -MF $(DEPDIR)/test_address_fake-test-common.Tpo -c -o test_address_fake-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_fake-test-common.Tpo $(DEPDIR)/test_address_fake-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_address_fake-test-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_fake-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c + +test_address_fake-test-common.obj: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_fake-test-common.obj -MD -MP -MF $(DEPDIR)/test_address_fake-test-common.Tpo -c -o test_address_fake-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_fake-test-common.Tpo $(DEPDIR)/test_address_fake-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_address_fake-test-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_fake-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` + +test_address_linux-test-address.o: test-address.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_linux-test-address.o -MD -MP -MF $(DEPDIR)/test_address_linux-test-address.Tpo -c -o test_address_linux-test-address.o `test -f 'test-address.c' || echo '$(srcdir)/'`test-address.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_linux-test-address.Tpo $(DEPDIR)/test_address_linux-test-address.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-address.c' object='test_address_linux-test-address.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_linux-test-address.o `test -f 'test-address.c' || echo '$(srcdir)/'`test-address.c + +test_address_linux-test-address.obj: test-address.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_linux-test-address.obj -MD -MP -MF $(DEPDIR)/test_address_linux-test-address.Tpo -c -o test_address_linux-test-address.obj `if test -f 'test-address.c'; then $(CYGPATH_W) 'test-address.c'; else $(CYGPATH_W) '$(srcdir)/test-address.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_linux-test-address.Tpo $(DEPDIR)/test_address_linux-test-address.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-address.c' object='test_address_linux-test-address.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_linux-test-address.obj `if test -f 'test-address.c'; then $(CYGPATH_W) 'test-address.c'; else $(CYGPATH_W) '$(srcdir)/test-address.c'; fi` + +test_address_linux-nm-platform.o: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_linux-nm-platform.o -MD -MP -MF $(DEPDIR)/test_address_linux-nm-platform.Tpo -c -o test_address_linux-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_linux-nm-platform.Tpo $(DEPDIR)/test_address_linux-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_address_linux-nm-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_linux-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c + +test_address_linux-nm-platform.obj: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_linux-nm-platform.obj -MD -MP -MF $(DEPDIR)/test_address_linux-nm-platform.Tpo -c -o test_address_linux-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_linux-nm-platform.Tpo $(DEPDIR)/test_address_linux-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_address_linux-nm-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_linux-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` + +test_address_linux-nm-fake-platform.o: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_linux-nm-fake-platform.o -MD -MP -MF $(DEPDIR)/test_address_linux-nm-fake-platform.Tpo -c -o test_address_linux-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_linux-nm-fake-platform.Tpo $(DEPDIR)/test_address_linux-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_address_linux-nm-fake-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_linux-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c + +test_address_linux-nm-fake-platform.obj: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_linux-nm-fake-platform.obj -MD -MP -MF $(DEPDIR)/test_address_linux-nm-fake-platform.Tpo -c -o test_address_linux-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_linux-nm-fake-platform.Tpo $(DEPDIR)/test_address_linux-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_address_linux-nm-fake-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_linux-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` + +test_address_linux-nm-linux-platform.o: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_linux-nm-linux-platform.o -MD -MP -MF $(DEPDIR)/test_address_linux-nm-linux-platform.Tpo -c -o test_address_linux-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_linux-nm-linux-platform.Tpo $(DEPDIR)/test_address_linux-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_address_linux-nm-linux-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_linux-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c + +test_address_linux-nm-linux-platform.obj: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_linux-nm-linux-platform.obj -MD -MP -MF $(DEPDIR)/test_address_linux-nm-linux-platform.Tpo -c -o test_address_linux-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_linux-nm-linux-platform.Tpo $(DEPDIR)/test_address_linux-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_address_linux-nm-linux-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_linux-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` + +test_address_linux-test-common.o: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_linux-test-common.o -MD -MP -MF $(DEPDIR)/test_address_linux-test-common.Tpo -c -o test_address_linux-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_linux-test-common.Tpo $(DEPDIR)/test_address_linux-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_address_linux-test-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_linux-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c + +test_address_linux-test-common.obj: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_address_linux-test-common.obj -MD -MP -MF $(DEPDIR)/test_address_linux-test-common.Tpo -c -o test_address_linux-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_address_linux-test-common.Tpo $(DEPDIR)/test_address_linux-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_address_linux-test-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_address_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_address_linux-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` + +test_cleanup_fake-test-cleanup.o: test-cleanup.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_fake-test-cleanup.o -MD -MP -MF $(DEPDIR)/test_cleanup_fake-test-cleanup.Tpo -c -o test_cleanup_fake-test-cleanup.o `test -f 'test-cleanup.c' || echo '$(srcdir)/'`test-cleanup.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_fake-test-cleanup.Tpo $(DEPDIR)/test_cleanup_fake-test-cleanup.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-cleanup.c' object='test_cleanup_fake-test-cleanup.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_fake-test-cleanup.o `test -f 'test-cleanup.c' || echo '$(srcdir)/'`test-cleanup.c + +test_cleanup_fake-test-cleanup.obj: test-cleanup.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_fake-test-cleanup.obj -MD -MP -MF $(DEPDIR)/test_cleanup_fake-test-cleanup.Tpo -c -o test_cleanup_fake-test-cleanup.obj `if test -f 'test-cleanup.c'; then $(CYGPATH_W) 'test-cleanup.c'; else $(CYGPATH_W) '$(srcdir)/test-cleanup.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_fake-test-cleanup.Tpo $(DEPDIR)/test_cleanup_fake-test-cleanup.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-cleanup.c' object='test_cleanup_fake-test-cleanup.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_fake-test-cleanup.obj `if test -f 'test-cleanup.c'; then $(CYGPATH_W) 'test-cleanup.c'; else $(CYGPATH_W) '$(srcdir)/test-cleanup.c'; fi` + +test_cleanup_fake-nm-platform.o: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_fake-nm-platform.o -MD -MP -MF $(DEPDIR)/test_cleanup_fake-nm-platform.Tpo -c -o test_cleanup_fake-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_fake-nm-platform.Tpo $(DEPDIR)/test_cleanup_fake-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_cleanup_fake-nm-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_fake-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c + +test_cleanup_fake-nm-platform.obj: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_fake-nm-platform.obj -MD -MP -MF $(DEPDIR)/test_cleanup_fake-nm-platform.Tpo -c -o test_cleanup_fake-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_fake-nm-platform.Tpo $(DEPDIR)/test_cleanup_fake-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_cleanup_fake-nm-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_fake-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` + +test_cleanup_fake-nm-fake-platform.o: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_fake-nm-fake-platform.o -MD -MP -MF $(DEPDIR)/test_cleanup_fake-nm-fake-platform.Tpo -c -o test_cleanup_fake-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_fake-nm-fake-platform.Tpo $(DEPDIR)/test_cleanup_fake-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_cleanup_fake-nm-fake-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_fake-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c + +test_cleanup_fake-nm-fake-platform.obj: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_fake-nm-fake-platform.obj -MD -MP -MF $(DEPDIR)/test_cleanup_fake-nm-fake-platform.Tpo -c -o test_cleanup_fake-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_fake-nm-fake-platform.Tpo $(DEPDIR)/test_cleanup_fake-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_cleanup_fake-nm-fake-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_fake-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` + +test_cleanup_fake-nm-linux-platform.o: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_fake-nm-linux-platform.o -MD -MP -MF $(DEPDIR)/test_cleanup_fake-nm-linux-platform.Tpo -c -o test_cleanup_fake-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_fake-nm-linux-platform.Tpo $(DEPDIR)/test_cleanup_fake-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_cleanup_fake-nm-linux-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_fake-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c + +test_cleanup_fake-nm-linux-platform.obj: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_fake-nm-linux-platform.obj -MD -MP -MF $(DEPDIR)/test_cleanup_fake-nm-linux-platform.Tpo -c -o test_cleanup_fake-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_fake-nm-linux-platform.Tpo $(DEPDIR)/test_cleanup_fake-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_cleanup_fake-nm-linux-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_fake-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` + +test_cleanup_fake-test-common.o: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_fake-test-common.o -MD -MP -MF $(DEPDIR)/test_cleanup_fake-test-common.Tpo -c -o test_cleanup_fake-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_fake-test-common.Tpo $(DEPDIR)/test_cleanup_fake-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_cleanup_fake-test-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_fake-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c + +test_cleanup_fake-test-common.obj: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_fake-test-common.obj -MD -MP -MF $(DEPDIR)/test_cleanup_fake-test-common.Tpo -c -o test_cleanup_fake-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_fake-test-common.Tpo $(DEPDIR)/test_cleanup_fake-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_cleanup_fake-test-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_fake-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` + +test_cleanup_linux-test-cleanup.o: test-cleanup.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_linux-test-cleanup.o -MD -MP -MF $(DEPDIR)/test_cleanup_linux-test-cleanup.Tpo -c -o test_cleanup_linux-test-cleanup.o `test -f 'test-cleanup.c' || echo '$(srcdir)/'`test-cleanup.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_linux-test-cleanup.Tpo $(DEPDIR)/test_cleanup_linux-test-cleanup.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-cleanup.c' object='test_cleanup_linux-test-cleanup.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_linux-test-cleanup.o `test -f 'test-cleanup.c' || echo '$(srcdir)/'`test-cleanup.c + +test_cleanup_linux-test-cleanup.obj: test-cleanup.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_linux-test-cleanup.obj -MD -MP -MF $(DEPDIR)/test_cleanup_linux-test-cleanup.Tpo -c -o test_cleanup_linux-test-cleanup.obj `if test -f 'test-cleanup.c'; then $(CYGPATH_W) 'test-cleanup.c'; else $(CYGPATH_W) '$(srcdir)/test-cleanup.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_linux-test-cleanup.Tpo $(DEPDIR)/test_cleanup_linux-test-cleanup.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-cleanup.c' object='test_cleanup_linux-test-cleanup.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_linux-test-cleanup.obj `if test -f 'test-cleanup.c'; then $(CYGPATH_W) 'test-cleanup.c'; else $(CYGPATH_W) '$(srcdir)/test-cleanup.c'; fi` + +test_cleanup_linux-nm-platform.o: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_linux-nm-platform.o -MD -MP -MF $(DEPDIR)/test_cleanup_linux-nm-platform.Tpo -c -o test_cleanup_linux-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_linux-nm-platform.Tpo $(DEPDIR)/test_cleanup_linux-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_cleanup_linux-nm-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_linux-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c + +test_cleanup_linux-nm-platform.obj: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_linux-nm-platform.obj -MD -MP -MF $(DEPDIR)/test_cleanup_linux-nm-platform.Tpo -c -o test_cleanup_linux-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_linux-nm-platform.Tpo $(DEPDIR)/test_cleanup_linux-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_cleanup_linux-nm-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_linux-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` + +test_cleanup_linux-nm-fake-platform.o: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_linux-nm-fake-platform.o -MD -MP -MF $(DEPDIR)/test_cleanup_linux-nm-fake-platform.Tpo -c -o test_cleanup_linux-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_linux-nm-fake-platform.Tpo $(DEPDIR)/test_cleanup_linux-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_cleanup_linux-nm-fake-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_linux-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c + +test_cleanup_linux-nm-fake-platform.obj: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_linux-nm-fake-platform.obj -MD -MP -MF $(DEPDIR)/test_cleanup_linux-nm-fake-platform.Tpo -c -o test_cleanup_linux-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_linux-nm-fake-platform.Tpo $(DEPDIR)/test_cleanup_linux-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_cleanup_linux-nm-fake-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_linux-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` + +test_cleanup_linux-nm-linux-platform.o: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_linux-nm-linux-platform.o -MD -MP -MF $(DEPDIR)/test_cleanup_linux-nm-linux-platform.Tpo -c -o test_cleanup_linux-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_linux-nm-linux-platform.Tpo $(DEPDIR)/test_cleanup_linux-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_cleanup_linux-nm-linux-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_linux-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c + +test_cleanup_linux-nm-linux-platform.obj: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_linux-nm-linux-platform.obj -MD -MP -MF $(DEPDIR)/test_cleanup_linux-nm-linux-platform.Tpo -c -o test_cleanup_linux-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_linux-nm-linux-platform.Tpo $(DEPDIR)/test_cleanup_linux-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_cleanup_linux-nm-linux-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_linux-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` + +test_cleanup_linux-test-common.o: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_linux-test-common.o -MD -MP -MF $(DEPDIR)/test_cleanup_linux-test-common.Tpo -c -o test_cleanup_linux-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_linux-test-common.Tpo $(DEPDIR)/test_cleanup_linux-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_cleanup_linux-test-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_linux-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c + +test_cleanup_linux-test-common.obj: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_cleanup_linux-test-common.obj -MD -MP -MF $(DEPDIR)/test_cleanup_linux-test-common.Tpo -c -o test_cleanup_linux-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_cleanup_linux-test-common.Tpo $(DEPDIR)/test_cleanup_linux-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_cleanup_linux-test-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_cleanup_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_cleanup_linux-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` + +test_link_fake-test-link.o: test-link.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_fake-test-link.o -MD -MP -MF $(DEPDIR)/test_link_fake-test-link.Tpo -c -o test_link_fake-test-link.o `test -f 'test-link.c' || echo '$(srcdir)/'`test-link.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_fake-test-link.Tpo $(DEPDIR)/test_link_fake-test-link.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-link.c' object='test_link_fake-test-link.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_fake-test-link.o `test -f 'test-link.c' || echo '$(srcdir)/'`test-link.c + +test_link_fake-test-link.obj: test-link.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_fake-test-link.obj -MD -MP -MF $(DEPDIR)/test_link_fake-test-link.Tpo -c -o test_link_fake-test-link.obj `if test -f 'test-link.c'; then $(CYGPATH_W) 'test-link.c'; else $(CYGPATH_W) '$(srcdir)/test-link.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_fake-test-link.Tpo $(DEPDIR)/test_link_fake-test-link.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-link.c' object='test_link_fake-test-link.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_fake-test-link.obj `if test -f 'test-link.c'; then $(CYGPATH_W) 'test-link.c'; else $(CYGPATH_W) '$(srcdir)/test-link.c'; fi` + +test_link_fake-nm-platform.o: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_fake-nm-platform.o -MD -MP -MF $(DEPDIR)/test_link_fake-nm-platform.Tpo -c -o test_link_fake-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_fake-nm-platform.Tpo $(DEPDIR)/test_link_fake-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_link_fake-nm-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_fake-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c + +test_link_fake-nm-platform.obj: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_fake-nm-platform.obj -MD -MP -MF $(DEPDIR)/test_link_fake-nm-platform.Tpo -c -o test_link_fake-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_fake-nm-platform.Tpo $(DEPDIR)/test_link_fake-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_link_fake-nm-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_fake-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` + +test_link_fake-nm-fake-platform.o: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_fake-nm-fake-platform.o -MD -MP -MF $(DEPDIR)/test_link_fake-nm-fake-platform.Tpo -c -o test_link_fake-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_fake-nm-fake-platform.Tpo $(DEPDIR)/test_link_fake-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_link_fake-nm-fake-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_fake-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c + +test_link_fake-nm-fake-platform.obj: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_fake-nm-fake-platform.obj -MD -MP -MF $(DEPDIR)/test_link_fake-nm-fake-platform.Tpo -c -o test_link_fake-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_fake-nm-fake-platform.Tpo $(DEPDIR)/test_link_fake-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_link_fake-nm-fake-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_fake-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` + +test_link_fake-nm-linux-platform.o: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_fake-nm-linux-platform.o -MD -MP -MF $(DEPDIR)/test_link_fake-nm-linux-platform.Tpo -c -o test_link_fake-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_fake-nm-linux-platform.Tpo $(DEPDIR)/test_link_fake-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_link_fake-nm-linux-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_fake-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c + +test_link_fake-nm-linux-platform.obj: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_fake-nm-linux-platform.obj -MD -MP -MF $(DEPDIR)/test_link_fake-nm-linux-platform.Tpo -c -o test_link_fake-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_fake-nm-linux-platform.Tpo $(DEPDIR)/test_link_fake-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_link_fake-nm-linux-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_fake-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` + +test_link_fake-test-common.o: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_fake-test-common.o -MD -MP -MF $(DEPDIR)/test_link_fake-test-common.Tpo -c -o test_link_fake-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_fake-test-common.Tpo $(DEPDIR)/test_link_fake-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_link_fake-test-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_fake-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c + +test_link_fake-test-common.obj: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_fake-test-common.obj -MD -MP -MF $(DEPDIR)/test_link_fake-test-common.Tpo -c -o test_link_fake-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_fake-test-common.Tpo $(DEPDIR)/test_link_fake-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_link_fake-test-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_fake-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` + +test_link_linux-test-link.o: test-link.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_linux-test-link.o -MD -MP -MF $(DEPDIR)/test_link_linux-test-link.Tpo -c -o test_link_linux-test-link.o `test -f 'test-link.c' || echo '$(srcdir)/'`test-link.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_linux-test-link.Tpo $(DEPDIR)/test_link_linux-test-link.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-link.c' object='test_link_linux-test-link.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_linux-test-link.o `test -f 'test-link.c' || echo '$(srcdir)/'`test-link.c + +test_link_linux-test-link.obj: test-link.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_linux-test-link.obj -MD -MP -MF $(DEPDIR)/test_link_linux-test-link.Tpo -c -o test_link_linux-test-link.obj `if test -f 'test-link.c'; then $(CYGPATH_W) 'test-link.c'; else $(CYGPATH_W) '$(srcdir)/test-link.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_linux-test-link.Tpo $(DEPDIR)/test_link_linux-test-link.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-link.c' object='test_link_linux-test-link.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_linux-test-link.obj `if test -f 'test-link.c'; then $(CYGPATH_W) 'test-link.c'; else $(CYGPATH_W) '$(srcdir)/test-link.c'; fi` + +test_link_linux-nm-platform.o: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_linux-nm-platform.o -MD -MP -MF $(DEPDIR)/test_link_linux-nm-platform.Tpo -c -o test_link_linux-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_linux-nm-platform.Tpo $(DEPDIR)/test_link_linux-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_link_linux-nm-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_linux-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c + +test_link_linux-nm-platform.obj: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_linux-nm-platform.obj -MD -MP -MF $(DEPDIR)/test_link_linux-nm-platform.Tpo -c -o test_link_linux-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_linux-nm-platform.Tpo $(DEPDIR)/test_link_linux-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_link_linux-nm-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_linux-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` + +test_link_linux-nm-fake-platform.o: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_linux-nm-fake-platform.o -MD -MP -MF $(DEPDIR)/test_link_linux-nm-fake-platform.Tpo -c -o test_link_linux-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_linux-nm-fake-platform.Tpo $(DEPDIR)/test_link_linux-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_link_linux-nm-fake-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_linux-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c + +test_link_linux-nm-fake-platform.obj: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_linux-nm-fake-platform.obj -MD -MP -MF $(DEPDIR)/test_link_linux-nm-fake-platform.Tpo -c -o test_link_linux-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_linux-nm-fake-platform.Tpo $(DEPDIR)/test_link_linux-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_link_linux-nm-fake-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_linux-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` + +test_link_linux-nm-linux-platform.o: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_linux-nm-linux-platform.o -MD -MP -MF $(DEPDIR)/test_link_linux-nm-linux-platform.Tpo -c -o test_link_linux-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_linux-nm-linux-platform.Tpo $(DEPDIR)/test_link_linux-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_link_linux-nm-linux-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_linux-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c + +test_link_linux-nm-linux-platform.obj: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_linux-nm-linux-platform.obj -MD -MP -MF $(DEPDIR)/test_link_linux-nm-linux-platform.Tpo -c -o test_link_linux-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_linux-nm-linux-platform.Tpo $(DEPDIR)/test_link_linux-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_link_linux-nm-linux-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_linux-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` + +test_link_linux-test-common.o: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_linux-test-common.o -MD -MP -MF $(DEPDIR)/test_link_linux-test-common.Tpo -c -o test_link_linux-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_linux-test-common.Tpo $(DEPDIR)/test_link_linux-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_link_linux-test-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_linux-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c + +test_link_linux-test-common.obj: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_link_linux-test-common.obj -MD -MP -MF $(DEPDIR)/test_link_linux-test-common.Tpo -c -o test_link_linux-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_link_linux-test-common.Tpo $(DEPDIR)/test_link_linux-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_link_linux-test-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_link_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_link_linux-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` + +test_route_fake-test-route.o: test-route.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_fake-test-route.o -MD -MP -MF $(DEPDIR)/test_route_fake-test-route.Tpo -c -o test_route_fake-test-route.o `test -f 'test-route.c' || echo '$(srcdir)/'`test-route.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_fake-test-route.Tpo $(DEPDIR)/test_route_fake-test-route.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-route.c' object='test_route_fake-test-route.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_fake-test-route.o `test -f 'test-route.c' || echo '$(srcdir)/'`test-route.c + +test_route_fake-test-route.obj: test-route.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_fake-test-route.obj -MD -MP -MF $(DEPDIR)/test_route_fake-test-route.Tpo -c -o test_route_fake-test-route.obj `if test -f 'test-route.c'; then $(CYGPATH_W) 'test-route.c'; else $(CYGPATH_W) '$(srcdir)/test-route.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_fake-test-route.Tpo $(DEPDIR)/test_route_fake-test-route.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-route.c' object='test_route_fake-test-route.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_fake-test-route.obj `if test -f 'test-route.c'; then $(CYGPATH_W) 'test-route.c'; else $(CYGPATH_W) '$(srcdir)/test-route.c'; fi` + +test_route_fake-nm-platform.o: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_fake-nm-platform.o -MD -MP -MF $(DEPDIR)/test_route_fake-nm-platform.Tpo -c -o test_route_fake-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_fake-nm-platform.Tpo $(DEPDIR)/test_route_fake-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_route_fake-nm-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_fake-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c + +test_route_fake-nm-platform.obj: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_fake-nm-platform.obj -MD -MP -MF $(DEPDIR)/test_route_fake-nm-platform.Tpo -c -o test_route_fake-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_fake-nm-platform.Tpo $(DEPDIR)/test_route_fake-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_route_fake-nm-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_fake-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` + +test_route_fake-nm-fake-platform.o: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_fake-nm-fake-platform.o -MD -MP -MF $(DEPDIR)/test_route_fake-nm-fake-platform.Tpo -c -o test_route_fake-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_fake-nm-fake-platform.Tpo $(DEPDIR)/test_route_fake-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_route_fake-nm-fake-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_fake-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c + +test_route_fake-nm-fake-platform.obj: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_fake-nm-fake-platform.obj -MD -MP -MF $(DEPDIR)/test_route_fake-nm-fake-platform.Tpo -c -o test_route_fake-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_fake-nm-fake-platform.Tpo $(DEPDIR)/test_route_fake-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_route_fake-nm-fake-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_fake-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` + +test_route_fake-nm-linux-platform.o: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_fake-nm-linux-platform.o -MD -MP -MF $(DEPDIR)/test_route_fake-nm-linux-platform.Tpo -c -o test_route_fake-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_fake-nm-linux-platform.Tpo $(DEPDIR)/test_route_fake-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_route_fake-nm-linux-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_fake-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c + +test_route_fake-nm-linux-platform.obj: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_fake-nm-linux-platform.obj -MD -MP -MF $(DEPDIR)/test_route_fake-nm-linux-platform.Tpo -c -o test_route_fake-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_fake-nm-linux-platform.Tpo $(DEPDIR)/test_route_fake-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_route_fake-nm-linux-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_fake-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` + +test_route_fake-test-common.o: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_fake-test-common.o -MD -MP -MF $(DEPDIR)/test_route_fake-test-common.Tpo -c -o test_route_fake-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_fake-test-common.Tpo $(DEPDIR)/test_route_fake-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_route_fake-test-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_fake-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c + +test_route_fake-test-common.obj: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_fake-test-common.obj -MD -MP -MF $(DEPDIR)/test_route_fake-test-common.Tpo -c -o test_route_fake-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_fake-test-common.Tpo $(DEPDIR)/test_route_fake-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_route_fake-test-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_fake_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_fake-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` + +test_route_linux-test-route.o: test-route.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_linux-test-route.o -MD -MP -MF $(DEPDIR)/test_route_linux-test-route.Tpo -c -o test_route_linux-test-route.o `test -f 'test-route.c' || echo '$(srcdir)/'`test-route.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_linux-test-route.Tpo $(DEPDIR)/test_route_linux-test-route.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-route.c' object='test_route_linux-test-route.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_linux-test-route.o `test -f 'test-route.c' || echo '$(srcdir)/'`test-route.c + +test_route_linux-test-route.obj: test-route.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_linux-test-route.obj -MD -MP -MF $(DEPDIR)/test_route_linux-test-route.Tpo -c -o test_route_linux-test-route.obj `if test -f 'test-route.c'; then $(CYGPATH_W) 'test-route.c'; else $(CYGPATH_W) '$(srcdir)/test-route.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_linux-test-route.Tpo $(DEPDIR)/test_route_linux-test-route.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-route.c' object='test_route_linux-test-route.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_linux-test-route.obj `if test -f 'test-route.c'; then $(CYGPATH_W) 'test-route.c'; else $(CYGPATH_W) '$(srcdir)/test-route.c'; fi` + +test_route_linux-nm-platform.o: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_linux-nm-platform.o -MD -MP -MF $(DEPDIR)/test_route_linux-nm-platform.Tpo -c -o test_route_linux-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_linux-nm-platform.Tpo $(DEPDIR)/test_route_linux-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_route_linux-nm-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_linux-nm-platform.o `test -f '../nm-platform.c' || echo '$(srcdir)/'`../nm-platform.c + +test_route_linux-nm-platform.obj: ../nm-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_linux-nm-platform.obj -MD -MP -MF $(DEPDIR)/test_route_linux-nm-platform.Tpo -c -o test_route_linux-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_linux-nm-platform.Tpo $(DEPDIR)/test_route_linux-nm-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-platform.c' object='test_route_linux-nm-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_linux-nm-platform.obj `if test -f '../nm-platform.c'; then $(CYGPATH_W) '../nm-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-platform.c'; fi` + +test_route_linux-nm-fake-platform.o: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_linux-nm-fake-platform.o -MD -MP -MF $(DEPDIR)/test_route_linux-nm-fake-platform.Tpo -c -o test_route_linux-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_linux-nm-fake-platform.Tpo $(DEPDIR)/test_route_linux-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_route_linux-nm-fake-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_linux-nm-fake-platform.o `test -f '../nm-fake-platform.c' || echo '$(srcdir)/'`../nm-fake-platform.c + +test_route_linux-nm-fake-platform.obj: ../nm-fake-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_linux-nm-fake-platform.obj -MD -MP -MF $(DEPDIR)/test_route_linux-nm-fake-platform.Tpo -c -o test_route_linux-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_linux-nm-fake-platform.Tpo $(DEPDIR)/test_route_linux-nm-fake-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-fake-platform.c' object='test_route_linux-nm-fake-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_linux-nm-fake-platform.obj `if test -f '../nm-fake-platform.c'; then $(CYGPATH_W) '../nm-fake-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-fake-platform.c'; fi` + +test_route_linux-nm-linux-platform.o: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_linux-nm-linux-platform.o -MD -MP -MF $(DEPDIR)/test_route_linux-nm-linux-platform.Tpo -c -o test_route_linux-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_linux-nm-linux-platform.Tpo $(DEPDIR)/test_route_linux-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_route_linux-nm-linux-platform.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_linux-nm-linux-platform.o `test -f '../nm-linux-platform.c' || echo '$(srcdir)/'`../nm-linux-platform.c + +test_route_linux-nm-linux-platform.obj: ../nm-linux-platform.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_linux-nm-linux-platform.obj -MD -MP -MF $(DEPDIR)/test_route_linux-nm-linux-platform.Tpo -c -o test_route_linux-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_linux-nm-linux-platform.Tpo $(DEPDIR)/test_route_linux-nm-linux-platform.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-linux-platform.c' object='test_route_linux-nm-linux-platform.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_linux-nm-linux-platform.obj `if test -f '../nm-linux-platform.c'; then $(CYGPATH_W) '../nm-linux-platform.c'; else $(CYGPATH_W) '$(srcdir)/../nm-linux-platform.c'; fi` + +test_route_linux-test-common.o: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_linux-test-common.o -MD -MP -MF $(DEPDIR)/test_route_linux-test-common.Tpo -c -o test_route_linux-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_linux-test-common.Tpo $(DEPDIR)/test_route_linux-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_route_linux-test-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_linux-test-common.o `test -f 'test-common.c' || echo '$(srcdir)/'`test-common.c + +test_route_linux-test-common.obj: test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_route_linux-test-common.obj -MD -MP -MF $(DEPDIR)/test_route_linux-test-common.Tpo -c -o test_route_linux-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_route_linux-test-common.Tpo $(DEPDIR)/test_route_linux-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-common.c' object='test_route_linux-test-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_route_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_linux-test-common.obj `if test -f 'test-common.c'; then $(CYGPATH_W) 'test-common.c'; else $(CYGPATH_W) '$(srcdir)/test-common.c'; fi` + +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 + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi + +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 +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + 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: + +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." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + 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-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: + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \ + clean-generic clean-libtool clean-noinstPROGRAMS 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-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 + + +@GNOME_CODE_COVERAGE_RULES@ + +# 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/platform/tests/dump.c b/src/platform/tests/dump.c new file mode 100644 index 00000000..e97ef138 --- /dev/null +++ b/src/platform/tests/dump.c @@ -0,0 +1,136 @@ +#include <stdio.h> +#include <stdlib.h> +#include <arpa/inet.h> + +#include "nm-platform.h" +#include "nm-linux-platform.h" +#include "nm-fake-platform.h" + +static void +dump_interface (NMPlatformLink *link) +{ + GArray *ip6_addresses; + GArray *ip4_addresses; + const NMPlatformIP6Address *ip6_address; + const NMPlatformIP4Address *ip4_address; + GArray *ip6_routes; + GArray *ip4_routes; + const NMPlatformIP6Route *ip6_route; + const NMPlatformIP4Route *ip4_route; + char networkstr[INET6_ADDRSTRLEN]; + char gatewaystr[INET6_ADDRSTRLEN]; + int vlan_id, vlan_parent; + const char *address; + size_t addrlen; + int i; + + g_assert (link->up || !link->connected); + + printf ("%d: %s: %s", link->ifindex, link->name, link->type_name); + if (link->up) + printf (" %s", link->connected ? "CONNECTED" : "DISCONNECTED"); + else + printf (" DOWN"); + if (!link->arp) + printf (" noarp"); + if (link->master) + printf (" master %d", link->master); + if (link->parent) + printf (" parent %d", link->parent); + printf (" mtu %d", link->mtu); + printf ("\n"); + if (link->driver) + printf (" driver: %s\n", link->driver); + printf (" UDI: %s\n", link->udi); + if (!nm_platform_vlan_get_info (link->ifindex, &vlan_parent, &vlan_id)) + g_assert_not_reached (); + if (vlan_parent) + printf (" vlan parent %d id %d\n", vlan_parent, vlan_id); + + if (nm_platform_link_is_software (link->ifindex)) + printf (" class software\n"); + if (nm_platform_link_supports_slaves (link->ifindex)) + printf (" class supports-slaves\n"); + if (nm_platform_link_supports_carrier_detect (link->ifindex)) + printf (" feature carrier-detect\n"); + if (nm_platform_link_supports_vlans (link->ifindex)) + printf (" feature vlans\n"); + + address = nm_platform_link_get_address (link->ifindex, &addrlen); + if (address) { + printf (" link-address "); + for (i = 0; i < addrlen; i++) + printf ("%s%02hhx", i ? ":" : "", address[i]); + printf ("\n"); + } + + ip4_addresses = nm_platform_ip4_address_get_all (link->ifindex); + ip6_addresses = nm_platform_ip6_address_get_all (link->ifindex); + + g_assert (ip4_addresses); + g_assert (ip6_addresses); + + for (i = 0; i < ip4_addresses->len; i++) { + ip4_address = &g_array_index (ip4_addresses, NMPlatformIP4Address, i); + printf (" ip4-address %s\n", nm_platform_ip4_address_to_string (ip4_address)); + } + + for (i = 0; i < ip6_addresses->len; i++) { + ip6_address = &g_array_index (ip6_addresses, NMPlatformIP6Address, i); + printf (" ip6-address %s\n", nm_platform_ip6_address_to_string (ip6_address)); + } + + g_array_unref (ip4_addresses); + g_array_unref (ip6_addresses); + + ip4_routes = nm_platform_ip4_route_get_all (link->ifindex, TRUE); + ip6_routes = nm_platform_ip6_route_get_all (link->ifindex, TRUE); + + g_assert (ip4_routes); + g_assert (ip6_routes); + + for (i = 0; i < ip4_routes->len; i++) { + ip4_route = &g_array_index (ip4_routes, NMPlatformIP4Route, i); + inet_ntop (AF_INET, &ip4_route->network, networkstr, sizeof (networkstr)); + inet_ntop (AF_INET, &ip4_route->gateway, gatewaystr, sizeof (gatewaystr)); + printf (" ip4-route %s/%d via %s\n", networkstr, ip4_route->plen, gatewaystr); + } + + for (i = 0; i < ip6_routes->len; i++) { + ip6_route = &g_array_index (ip6_routes, NMPlatformIP6Route, i); + inet_ntop (AF_INET6, &ip6_route->network, networkstr, sizeof (networkstr)); + inet_ntop (AF_INET6, &ip6_route->gateway, gatewaystr, sizeof (gatewaystr)); + printf (" ip6-route %s/%d via %s\n", networkstr, ip6_route->plen, gatewaystr); + } + + g_array_unref (ip4_routes); + g_array_unref (ip6_routes); +} + +static void +dump_all (void) +{ + GArray *links = nm_platform_link_get_all (); + int i; + + for (i = 0; i < links->len; i++) + dump_interface (&g_array_index (links, NMPlatformLink, i)); +} + +int +main (int argc, char **argv) +{ +#if !GLIB_CHECK_VERSION (2, 35, 0) + g_type_init (); +#endif + + g_assert (argc <= 2); + if (argc > 1 && !g_strcmp0 (argv[1], "--fake")) + nm_fake_platform_setup (); + else + nm_linux_platform_setup (); + + dump_all (); + + return EXIT_SUCCESS; +} diff --git a/src/platform/tests/monitor.c b/src/platform/tests/monitor.c new file mode 100644 index 00000000..d56cc2bf --- /dev/null +++ b/src/platform/tests/monitor.c @@ -0,0 +1,30 @@ +#include <stdlib.h> +#include <syslog.h> + +#include "nm-fake-platform.h" +#include "nm-linux-platform.h" +#include "nm-logging.h" + +int +main (int argc, char **argv) +{ + GMainLoop *loop; + +#if !GLIB_CHECK_VERSION (2, 35, 0) + g_type_init (); +#endif + + loop = g_main_loop_new (NULL, FALSE); + nm_logging_setup ("debug", NULL, NULL, NULL); + openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR, LOG_DAEMON); + + g_assert (argc <= 2); + if (argc > 1 && !g_strcmp0 (argv[1], "--fake")) + nm_fake_platform_setup (); + else + nm_linux_platform_setup (); + + g_main_loop_run (loop); + + return EXIT_SUCCESS; +} diff --git a/src/platform/tests/platform.c b/src/platform/tests/platform.c new file mode 100644 index 00000000..ea8bd0e3 --- /dev/null +++ b/src/platform/tests/platform.c @@ -0,0 +1,897 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-platform.c - Handle runtime kernel networking configuration + * + * 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, 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) 2013 Red Hat, Inc. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <arpa/inet.h> +#include <netlink/route/addr.h> + +#include "nm-platform.h" +#include "nm-linux-platform.h" +#include "nm-fake-platform.h" + +#define error(...) fprintf (stderr, __VA_ARGS__) + +typedef gboolean boolean_t; +typedef int decimal_t; +typedef const char *string_t; + +#define print_boolean(value) printf ("%s\n", value ? "yes" : "no") +#define print_decimal(value) printf ("%d\n", value) +#define print_string(value) printf ("%s\n", value) + +static gboolean +do_sysctl_set (char **argv) +{ + return nm_platform_sysctl_set (argv[0], argv[1]); +} + +static gboolean +do_sysctl_get (char **argv) +{ + auto_g_free char *value = nm_platform_sysctl_get (argv[0]); + + printf ("%s\n", value); + + return !!value; +} + +static int +parse_ifindex (const char *str) +{ + char *endptr; + int ifindex = 0; + + ifindex = strtol (str, &endptr, 10); + + if (*endptr) { + ifindex = nm_platform_link_get_ifindex (str); + } + + return ifindex; +} + +static gboolean +do_link_get_all (char **argv) +{ + GArray *links; + NMPlatformLink *device; + int i; + + links = nm_platform_link_get_all (); + for (i = 0; i < links->len; i++) { + device = &g_array_index (links, NMPlatformLink, i); + + printf ("%d: %s type %d\n", device->ifindex, device->name, device->type); + } + g_array_unref (links); + + return TRUE; +} + +static gboolean +do_dummy_add (char **argv) +{ + return nm_platform_dummy_add (argv[0]); +} + +static gboolean +do_bridge_add (char **argv) +{ + return nm_platform_bridge_add (argv[0], NULL, 0); +} + +static gboolean +do_bond_add (char **argv) +{ + return nm_platform_bond_add (argv[0]); +} + +static gboolean +do_team_add (char **argv) +{ + return nm_platform_team_add (argv[0]); +} + +static gboolean +do_vlan_add (char **argv) +{ + const char *name = *argv++; + int parent = parse_ifindex (*argv++); + int vlanid = strtol (*argv++, NULL, 10); + guint32 vlan_flags = strtol (*argv++, NULL, 10); + + return nm_platform_vlan_add (name, parent, vlanid, vlan_flags); +} + +static gboolean +do_link_exists (char **argv) +{ + gboolean value = nm_platform_link_exists (argv[0]); + + print_boolean (value); + + return TRUE; +} + +#define LINK_CMD(cmdname) \ + static gboolean \ + do_link_##cmdname (char **argv) \ + { \ + int ifindex = parse_ifindex (argv[0]); \ + return ifindex ? nm_platform_link_##cmdname (ifindex) : FALSE; \ + } + +#define LINK_CMD_GET_FULL(cmdname, type, cond) \ + static gboolean \ + do_link_##cmdname (char **argv) \ + { \ + int ifindex = parse_ifindex (argv[0]); \ + if (ifindex) { \ + type##_t value = nm_platform_link_##cmdname (ifindex); \ + if (cond) { \ + print_##type (value); \ + return TRUE; \ + } \ + } \ + return FALSE; \ + } +#define LINK_CMD_GET(cmdname, type) LINK_CMD_GET_FULL (cmdname, type, TRUE); + +LINK_CMD (delete) + +/* do_link_delete_by_ifname: + * + * We don't need this as we allow ifname instead of ifindex anyway. + */ + +static gboolean +do_link_get_ifindex (char **argv) +{ + int ifindex = nm_platform_link_get_ifindex (argv[0]); + + if (ifindex) + printf ("%d\n", ifindex); + + return !!ifindex; +} + +LINK_CMD_GET_FULL (get_name, string, value) +LINK_CMD_GET_FULL (get_type, decimal, value > 0) +LINK_CMD_GET (is_software, boolean) +LINK_CMD_GET (supports_slaves, boolean) + +LINK_CMD (set_up) +LINK_CMD (set_down) +LINK_CMD (set_arp) +LINK_CMD (set_noarp) +LINK_CMD_GET (is_up, boolean) +LINK_CMD_GET (is_connected, boolean) +LINK_CMD_GET (uses_arp, boolean) + +static gboolean +do_link_set_address (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + char *hex = *argv++; + int hexlen = strlen (hex); + char address[hexlen/2]; + char *endptr; + int i; + + g_assert (!(hexlen % 2)); + + for (i = 0; i < sizeof (address); i++) { + char digit[3]; + + digit[0] = hex[2*i]; + digit[1] = hex[2*i+1]; + digit[2] = '\0'; + + address[i] = strtoul (digit, &endptr, 16); + g_assert (!*endptr); + } + + return nm_platform_link_set_address (ifindex, address, sizeof (address)); +} + +static gboolean +do_link_get_address (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + const char *address; + size_t length; + int i; + + address = nm_platform_link_get_address (ifindex, &length); + + if (!address || length <= 0) + return FALSE; + + for (i = 0; i < length; i++) + printf ("%02x", address[i]); + printf ("\n"); + + return TRUE; +} + +static gboolean +do_link_set_mtu (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + int mtu = strtoul (*argv++, NULL, 10); + + return nm_platform_link_set_mtu (ifindex, mtu); +} + +LINK_CMD_GET (get_mtu, decimal); +LINK_CMD_GET (supports_carrier_detect, boolean) +LINK_CMD_GET (supports_vlans, boolean) + +static gboolean +do_link_enslave (char **argv) +{ + int master = parse_ifindex (*argv++); + int slave = parse_ifindex (*argv++); + + return nm_platform_link_enslave (master, slave); +} + +static gboolean +do_link_release (char **argv) +{ + int master = parse_ifindex (*argv++); + int slave = parse_ifindex (*argv++); + + return nm_platform_link_release (master, slave); +} + +LINK_CMD_GET (get_master, decimal) + +static gboolean +do_master_set_option (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + const char *option = *argv++; + const char *value = *argv++; + + return nm_platform_master_set_option (ifindex, option, value); +} + +static gboolean +do_master_get_option (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + const char *option = *argv++; + auto_g_free char *value = nm_platform_master_get_option (ifindex, option); + + printf ("%s\n", value); + + return !!value; +} + +static gboolean +do_slave_set_option (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + const char *option = *argv++; + const char *value = *argv++; + + return nm_platform_slave_set_option (ifindex, option, value); +} + +static gboolean +do_slave_get_option (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + const char *option = *argv++; + auto_g_free char *value = nm_platform_slave_get_option (ifindex, option); + + printf ("%s\n", value); + + return !!value; +} + +static gboolean +do_vlan_get_info (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + int parent; + int vlanid; + + if (!nm_platform_vlan_get_info (ifindex, &parent, &vlanid)) + return FALSE; + + printf ("%d %d\n", parent, vlanid); + + return TRUE; +} + +static gboolean +do_vlan_set_ingress_map (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + int from = strtol (*argv++, NULL, 10); + int to = strtol (*argv++, NULL, 10); + + return nm_platform_vlan_set_ingress_map (ifindex, from, to); +} + +static gboolean +do_vlan_set_egress_map (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + int from = strtol (*argv++, NULL, 10); + int to = strtol (*argv++, NULL, 10); + + return nm_platform_vlan_set_egress_map (ifindex, from, to); +} + +static gboolean +do_veth_get_properties (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + NMPlatformVethProperties props; + + if (!nm_platform_veth_get_properties (ifindex, &props)) + return FALSE; + + printf ("peer: %d\n", props.peer); + + return TRUE; +} + +static gboolean +do_tun_get_properties (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + NMPlatformTunProperties props; + + if (!nm_platform_tun_get_properties (ifindex, &props)) + return FALSE; + + printf ("mode: %s\n", props.mode); + if (props.owner == -1) + printf ("owner: none\n"); + else + printf ("owner: %lu\n", (gulong) props.owner); + if (props.group == -1) + printf ("group: none\n"); + else + printf ("group: %lu\n", (gulong) props.group); + printf ("no-pi: "); + print_boolean (props.no_pi); + printf ("vnet-hdr: "); + print_boolean (props.vnet_hdr); + printf ("multi-queue: "); + print_boolean (props.multi_queue); + + return TRUE; +} + +static gboolean +do_macvlan_get_properties (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + NMPlatformMacvlanProperties props; + + if (!nm_platform_macvlan_get_properties (ifindex, &props)) + return FALSE; + + printf ("parent: %d\n", props.parent_ifindex); + printf ("mode: %s\n", props.mode); + printf ("no-promisc: "); + print_boolean (props.no_promisc); + return TRUE; +} + +static gboolean +do_vxlan_get_properties (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + NMPlatformVxlanProperties props; + char addrstr[INET6_ADDRSTRLEN]; + + if (!nm_platform_vxlan_get_properties (ifindex, &props)) + return FALSE; + + printf ("parent-ifindex: %u\n", props.parent_ifindex); + printf ("id: %u\n", props.id); + if (props.group) + inet_ntop (AF_INET, &props.group, addrstr, sizeof (addrstr)); + else if (props.group6.s6_addr[0]) + inet_ntop (AF_INET6, &props.group6, addrstr, sizeof (addrstr)); + else + strcpy (addrstr, "-"); + printf ("group: %s\n", addrstr); + if (props.local) + inet_ntop (AF_INET, &props.local, addrstr, sizeof (addrstr)); + else if (props.local6.s6_addr[0]) + inet_ntop (AF_INET6, &props.local6, addrstr, sizeof (addrstr)); + else + strcpy (addrstr, "-"); + printf ("local: %s\n", addrstr); + printf ("tos: %u\n", props.tos); + printf ("ttl: %u\n", props.ttl); + printf ("learning: "); + print_boolean (props.learning); + printf ("ageing: %u\n", props.ageing); + printf ("limit: %u\n", props.limit); + printf ("dst-port: %u\n", props.dst_port); + printf ("src-port-min: %u\n", props.src_port_min); + printf ("src-port-max: %u\n", props.src_port_max); + printf ("proxy: "); + print_boolean (props.proxy); + printf ("rsc: "); + print_boolean (props.rsc); + printf ("l2miss: "); + print_boolean (props.l2miss); + printf ("l3miss: "); + print_boolean (props.l3miss); + + return TRUE; +} + +static gboolean +do_gre_get_properties (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + NMPlatformGreProperties props; + char addrstr[INET_ADDRSTRLEN]; + + if (!nm_platform_gre_get_properties (ifindex, &props)) + return FALSE; + + printf ("parent-ifindex: %u\n", props.parent_ifindex); + printf ("input-flags: %u\n", props.input_flags); + printf ("output-flags: %u\n", props.input_flags); + printf ("input-key: %u\n", props.input_key); + printf ("output-key: %u\n", props.output_key); + if (props.local) + inet_ntop (AF_INET, &props.local, addrstr, sizeof (addrstr)); + else + strcpy (addrstr, "-"); + printf ("local: %s\n", addrstr); + if (props.remote) + inet_ntop (AF_INET, &props.remote, addrstr, sizeof (addrstr)); + else + strcpy (addrstr, "-"); + printf ("remote: %s\n", addrstr); + printf ("ttl: %u\n", props.ttl); + printf ("tos: %u\n", props.tos); + printf ("path-mtu-discovery: "); + print_boolean (props.path_mtu_discovery); + + return TRUE; +} + +static gboolean +do_ip4_address_get_all (char **argv) +{ + int ifindex = parse_ifindex (argv[0]); + GArray *addresses; + NMPlatformIP4Address *address; + char addrstr[INET_ADDRSTRLEN]; + int i; + + if (ifindex) { + addresses = nm_platform_ip4_address_get_all (ifindex); + for (i = 0; i < addresses->len; i++) { + address = &g_array_index (addresses, NMPlatformIP4Address, i); + inet_ntop (AF_INET, &address->address, addrstr, sizeof (addrstr)); + printf ("%s/%d\n", addrstr, address->plen); + } + g_array_unref (addresses); + } + + return !!ifindex; +} + +static gboolean +do_ip6_address_get_all (char **argv) +{ + int ifindex = parse_ifindex (argv[0]); + GArray *addresses; + NMPlatformIP6Address *address; + char addrstr[INET6_ADDRSTRLEN]; + int i; + + if (ifindex) { + addresses = nm_platform_ip6_address_get_all (ifindex); + for (i = 0; i < addresses->len; i++) { + address = &g_array_index (addresses, NMPlatformIP6Address, i); + inet_ntop (AF_INET6, &address->address, addrstr, sizeof (addrstr)); + printf ("%s/%d\n", addrstr, address->plen); + } + g_array_unref (addresses); + } + + return !!ifindex; +} + +static gboolean +parse_ip_address (int family, char *str, gpointer address, int *plen) +{ + char *endptr; + + if (plen) { + char *ptr = strchr (str, '/'); + if (ptr) { + *ptr++ = '\0'; + *plen = strtol (ptr, &endptr, 10); + if (*endptr) + ptr = NULL; + } + if (!ptr) { + error ("Bad format of IP address, expected address/plen.\n"); + return FALSE; + } + } + + if (inet_pton (family, str, address)) + return TRUE; + + error ("Bad format of IP address, expected address%s.\n", plen ? "/plen" : ""); + return FALSE; +} + +typedef in_addr_t ip4_t; +typedef struct in6_addr ip6_t; + +#define parse_ip4_address(s, a, p) parse_ip_address (AF_INET, s, a, p) +#define parse_ip6_address(s, a, p) parse_ip_address (AF_INET6, s, a, p) + +static gboolean +do_ip4_address_add (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + ip4_t address; + int plen; + + if (ifindex && parse_ip4_address (*argv++, &address, &plen)) { + guint32 lifetime = strtol (*argv++, NULL, 10); + guint32 preferred = strtol (*argv++, NULL, 10); + + gboolean value = nm_platform_ip4_address_add (ifindex, address, 0, plen, lifetime, preferred, NULL); + return value; + } else + return FALSE; +} + +static gboolean +do_ip6_address_add (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + ip6_t address; + int plen; + + if (ifindex && parse_ip6_address (*argv++, &address, &plen)) { + guint32 lifetime = strtol (*argv++, NULL, 10); + guint32 preferred = strtol (*argv++, NULL, 10); + guint flags = (*argv) ? rtnl_addr_str2flags (*argv++) : 0; + + gboolean value = nm_platform_ip6_address_add (ifindex, address, in6addr_any, plen, lifetime, preferred, flags); + return value; + } else + return FALSE; +} + +#define ADDR_CMD_FULL(v, cmdname, print) \ + static gboolean \ + do_##v##_address_##cmdname (char **argv) \ + { \ + int ifindex = parse_ifindex (*argv++); \ + v##_t address; \ + int plen; \ + if (ifindex && parse_##v##_address (*argv++, &address, &plen)) { \ + gboolean value = nm_platform_##v##_address_##cmdname (ifindex, address, plen); \ + if (print) { \ + print_boolean (value); \ + return TRUE; \ + } else \ + return value; \ + } else \ + return FALSE; \ + } +#define ADDR_CMD(cmdname) ADDR_CMD_FULL (ip4, cmdname, FALSE) ADDR_CMD_FULL (ip6, cmdname, FALSE) +#define ADDR_CMD_PRINT(cmdname) ADDR_CMD_FULL (ip4, cmdname, TRUE) ADDR_CMD_FULL (ip6, cmdname, TRUE) + +ADDR_CMD (delete) +ADDR_CMD_PRINT (exists) + +static gboolean +do_ip4_route_get_all (char **argv) +{ + int ifindex = parse_ifindex (argv[0]); + GArray *routes; + NMPlatformIP4Route *route; + char networkstr[INET_ADDRSTRLEN], gatewaystr[INET_ADDRSTRLEN]; + int i; + + if (ifindex) { + routes = nm_platform_ip4_route_get_all (ifindex, TRUE); + for (i = 0; i < routes->len; i++) { + route = &g_array_index (routes, NMPlatformIP4Route, i); + inet_ntop (AF_INET, &route->network, networkstr, sizeof (networkstr)); + inet_ntop (AF_INET, &route->gateway, gatewaystr, sizeof (gatewaystr)); + printf ("%s/%d via %s metric %d\n", + networkstr, route->plen, gatewaystr, route->metric); + } + g_array_unref (routes); + } + + return !!ifindex; +} + +static gboolean +do_ip6_route_get_all (char **argv) +{ + int ifindex = parse_ifindex (argv[0]); + GArray *routes; + NMPlatformIP6Route *route; + char networkstr[INET6_ADDRSTRLEN], gatewaystr[INET6_ADDRSTRLEN]; + int i; + + if (ifindex) { + routes = nm_platform_ip6_route_get_all (ifindex, TRUE); + for (i = 0; i < routes->len; i++) { + route = &g_array_index (routes, NMPlatformIP6Route, i); + inet_ntop (AF_INET6, &route->network, networkstr, sizeof (networkstr)); + inet_ntop (AF_INET6, &route->gateway, gatewaystr, sizeof (gatewaystr)); + printf ("%s/%d via %s metric %d\n", + networkstr, route->plen, gatewaystr, route->metric); + } + g_array_unref (routes); + } + + return !!ifindex; +} + +static gboolean +do_ip4_route_add (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + in_addr_t network, gateway; + int plen, metric, mss; + + parse_ip4_address (*argv++, &network, &plen); + parse_ip4_address (*argv++, &gateway, NULL); + metric = strtol (*argv++, NULL, 10); + mss = strtol (*argv++, NULL, 10); + + return nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, + network, plen, gateway, + metric, mss); +} + +static gboolean +do_ip6_route_add (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + struct in6_addr network, gateway; + int plen, metric, mss; + + parse_ip6_address (*argv++, &network, &plen); + parse_ip6_address (*argv++, &gateway, NULL); + metric = strtol (*argv++, NULL, 10); + mss = strtol (*argv++, NULL, 10); + return nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, + network, plen, gateway, + metric, mss); +} + +static gboolean +do_ip4_route_delete (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + in_addr_t network; + int plen, metric; + + parse_ip4_address (*argv++, &network, &plen); + metric = strtol (*argv++, NULL, 10); + + return nm_platform_ip4_route_delete (ifindex, network, plen, metric); +} + +static gboolean +do_ip6_route_delete (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + struct in6_addr network; + int plen, metric; + + parse_ip6_address (*argv++, &network, &plen); + metric = strtol (*argv++, NULL, 10); + + return nm_platform_ip6_route_delete (ifindex, network, plen, metric); +} + +static gboolean +do_ip4_route_exists (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + in_addr_t network; + int plen, metric; + + parse_ip4_address (*argv++, &network, &plen); + metric = strtol (*argv++, NULL, 10); + + print_boolean (nm_platform_ip4_route_exists (ifindex, network, plen, metric)); + return TRUE; +} + +static gboolean +do_ip6_route_exists (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + struct in6_addr network; + int plen, metric; + + parse_ip6_address (*argv++, &network, &plen); + metric = strtol (*argv++, NULL, 10); + + print_boolean (nm_platform_ip6_route_exists (ifindex, network, plen, metric)); + return TRUE; +} + +typedef struct { + const char *name; + const char *help; + int (*handler) (char **argv); + int argc; + const char *arghelp; +} command_t; + +static const command_t commands[] = { + { "sysctl-set", "get /proc/sys or /sys value", do_sysctl_set, 2, "<path> <value>" }, + { "sysctl-get", "get /proc/sys or /sys value", do_sysctl_get, 1, "<value>" }, + { "link-get-all", "print all links", do_link_get_all, 0, "" }, + { "dummy-add", "add dummy interface", do_dummy_add, 1, "<ifname>" }, + { "bridge-add", "add bridge interface", do_bridge_add, 1, "<ifname>" }, + { "bond-add", "add bond interface", do_bond_add, 1, "<ifname>" }, + { "team-add", "add team interface", do_team_add, 1, "<ifname>" }, + { "vlan-add", "add vlan interface", do_vlan_add, 4, "<ifname> <parent> <vlanid> <vlanflags>" }, + { "link-exists", "check ifname for existance", do_link_exists, 1, "<ifname>" }, + { "link-delete", "delete interface", do_link_delete, 1, "<ifname/ifindex>" }, + { "link-get-ifindex>", "get interface index", do_link_get_ifindex, 1, "<ifname>" }, + { "link-get-name", "get interface name", do_link_get_name, 1, "<ifindex>" }, + { "link-get-type", "get interface type", do_link_get_type, 1, "<ifname/ifindex>" }, + { "link-is-software", "check if interface is a software one", do_link_is_software, 1, "<ifname/ifindex>" }, + { "link-supports-slaves", "check if interface supports slaves", do_link_supports_slaves, 1, "<ifname/ifindex>" }, + { "link-set-up", "set interface up", do_link_set_up, 1, "<ifname/ifindex>" }, + { "link-set-down", "set interface down", do_link_set_down, 1, "<ifname/ifindex>" }, + { "link-set-arp", "activate interface arp", do_link_set_arp, 1, "<ifname/ifindex>" }, + { "link-set-noarp", "deactivate interface arp", do_link_set_noarp, 1, "<ifname/ifindex>" }, + { "link-is-up", "check if interface is up", do_link_is_up, 1, "<ifname/ifindex>" }, + { "link-is-connected", "check interface carrier", do_link_is_connected, 1, "<ifname/ifindex>" }, + { "link-uses-arp", "check whether interface uses arp", do_link_uses_arp, 1, "<ifname/ifindex>" }, + { "link-get-address", "print link address", do_link_get_address, 1, "<ifname/ifindex>" }, + { "link-set-address", "set link address", do_link_set_address, 2, "<ifname/ifindex> <hex>" }, + { "link-get-mtu", "print link mtu", do_link_get_mtu, 1, "<ifname/ifindex>" }, + { "link-set-mtu", "set link mtu", do_link_set_mtu, 2, "<ifname/ifindex> <mtu>" }, + { "link-supports-carrier-detect", "check whether interface supports carrier detect", + do_link_supports_carrier_detect, 1, "<ifname/ifindex>" }, + { "link-supports-vlans", "check whether interface supports VLANs", + do_link_supports_vlans, 1, "<ifname/ifindex>" }, + { "link-enslave", "enslave slave interface with master", do_link_enslave, 2, "<master> <slave>" }, + { "link-release", "release save interface from master", do_link_release, 2, "<master> <slave>" }, + { "link-get-master", "print master interface of a slave", do_link_get_master, 1, "<ifname/ifindex>" }, + { "link-master-set-option", "set master option", do_master_set_option, 3, + "<ifname/ifindex> <option> <value>" }, + { "link-master-get-option", "get master option", do_master_get_option, 2, + "<ifname/ifindex> <option>" }, + { "link-slave-set-option", "set slave option", do_slave_set_option, 3, + "<ifname/ifindex> <option>" }, + { "link-slave-get-option", "get slave option", do_slave_get_option, 2, + "<ifname/ifindex> <option>" }, + { "vlan-get-info", "get vlan info", do_vlan_get_info, 1, "<ifname/ifindex>" }, + { "vlan-set-ingress-map", "set vlan ingress map", do_vlan_set_ingress_map, 3, + "<ifname/ifindex> <from> <to>" }, + { "vlan-set-egress-map", "set vlan egress map", do_vlan_set_egress_map, 3, + "<ifname/ifindex> <from> <to>" }, + { "veth-get-properties", "get veth properties", do_veth_get_properties, 1, + "<ifname/ifindex>" }, + { "tun-get-properties", "get tun/tap properties", do_tun_get_properties, 1, + "<ifname/ifindex>" }, + { "macvlan-get-properties", "get macvlan properties", do_macvlan_get_properties, 1, + "<ifname/ifindex>" }, + { "vxlan-get-properties", "get vxlan properties", do_vxlan_get_properties, 1, + "<ifname/ifindex>" }, + { "gre-get-properties", "get gre properties", do_gre_get_properties, 1, + "<ifname/ifindex>" }, + { "ip4-address-get-all", "print all IPv4 addresses", do_ip4_address_get_all, 1, "<ifname/ifindex>" }, + { "ip6-address-get-all", "print all IPv6 addresses", do_ip6_address_get_all, 1, "<ifname/ifindex>" }, + { "ip4-address-add", "add IPv4 address", do_ip4_address_add, 4, "<ifname/ifindex> <address>/<plen> <lifetime> <>" }, + { "ip6-address-add", "add IPv6 address", do_ip6_address_add, 4, "<ifname/ifindex> <address>/<plen> <lifetime> [<flags>] <>" }, + { "ip4-address-delete", "delete IPv4 address", do_ip4_address_delete, 2, + "<ifname/ifindex> <address>/<plen>" }, + { "ip6-address-delete", "delete IPv6 address", do_ip6_address_delete, 2, + "<ifname/ifindex> <address>/<plen>" }, + { "ip4-address-exists", "check for existence of IPv4 address", do_ip4_address_exists, 2, + "<ifname/ifindex> <address>/<plen>" }, + { "ip6-address-exists", "check for existence of IPv6 address", do_ip6_address_exists, 2, + "<ifname/ifindex> <address>/<plen>" }, + { "ip4-route-get-all", "print all IPv4 routes", do_ip4_route_get_all, 1, "<ifname/ifindex>" }, + { "ip6-route-get-all", "print all IPv6 routes", do_ip6_route_get_all, 1, "<ifname/ifindex>" }, + { "ip4-route-add", "add IPv4 route", do_ip4_route_add, 5, + "<ifname/ifindex> <network>/<plen> <gateway> <metric> <mss>" }, + { "ip6-route-add", "add IPv6 route", do_ip6_route_add, 5, + "<ifname/ifindex> <network>/<plen> <gateway> <metric> <mss>" }, + { "ip4-route-delete", "delete IPv4 route", do_ip4_route_delete, 3, + "<ifname/ifindex> <network>/<plen> <metric>" }, + { "ip6-route-delete", "delete IPv6 route", do_ip6_route_delete, 3, + "<ifname/ifindex> <network>/<plen> <metric>" }, + { "ip4-route-exists", "check for existence of IPv4 route", do_ip4_route_exists, 3, + "<ifname/ifindex> <network>/<plen> <metric>" }, + { "ip6-route-exists", "check for existence of IPv6 route", do_ip6_route_exists, 3, + "<ifname/ifindex> <network>/<plen> <metric>" }, + { NULL, NULL, NULL, 0, NULL }, +}; + +int +main (int argc, char **argv) +{ + const char *arg0 = *argv++; + const command_t *command = NULL; + gboolean status = TRUE; + int error; + +#if !GLIB_CHECK_VERSION (2, 35, 0) + g_type_init (); +#endif + + if (*argv && !g_strcmp0 (argv[1], "--fake")) { + nm_fake_platform_setup (); + } else + nm_linux_platform_setup (); + + if (*argv) + for (command = commands; command->name; command++) + if (g_str_has_prefix (command->name, *argv)) + break; + + if (command && command->name) { + argv++; + if (g_strv_length (argv) == command->argc) + status = command->handler (argv); + else { + error ("Wrong number of arguments to '%s' (expected %d).\n\nUsage: %s %s %s\n-- %s\n", + command->name, command->argc, + arg0, command->name, command->arghelp, command->help); + return EXIT_FAILURE; + } + } else { + error ("Usage: %s COMMAND\n\n", arg0); + error ("COMMAND\n"); + for (command = commands; command->name; command++) + error (" %s %s\n -- %s\n", command->name, command->arghelp, command->help); + error ("\n"); + } + + error = nm_platform_get_error (); + if (error) { + const char *msg = nm_platform_get_error_msg (); + + error ("nm-platform: %s\n", msg); + } + + return !!error; +} diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c new file mode 100644 index 00000000..3fef5375 --- /dev/null +++ b/src/platform/tests/test-address.c @@ -0,0 +1,265 @@ +#include "test-common.h" + +#define DEVICE_NAME "nm-test-device" +#define IP4_ADDRESS "192.0.2.1" +#define IP4_PLEN 24 +#define IP6_ADDRESS "2001:db8:a:b:1:2:3:4" +#define IP6_PLEN 64 + +static void +ip4_address_callback (NMPlatform *platform, int ifindex, NMPlatformIP4Address *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data) +{ + g_assert (received); + g_assert_cmpint (received->ifindex, ==, ifindex); + g_assert (data && data->name); + g_assert_cmpstr (data->name, ==, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED); + + if (data->ifindex && data->ifindex != received->ifindex) + return; + if (data->change_type != change_type) + return; + + if (data->loop) + g_main_loop_quit (data->loop); + + if (data->received) + g_error ("Received signal '%s' a second time.", data->name); + + data->received = TRUE; +} + +static void +ip6_address_callback (NMPlatform *platform, int ifindex, NMPlatformIP6Address *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data) +{ + g_assert (received); + g_assert_cmpint (received->ifindex, ==, ifindex); + g_assert (data && data->name); + g_assert_cmpstr (data->name, ==, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED); + + if (data->ifindex && data->ifindex != received->ifindex) + return; + if (data->change_type != change_type) + return; + + if (data->loop) + g_main_loop_quit (data->loop); + + if (data->received) + g_error ("Received signal '%s' a second time.", data->name); + + data->received = TRUE; +} + +static void +test_ip4_address (void) +{ + int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME); + SignalData *address_added = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_address_callback, ifindex); + SignalData *address_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip4_address_callback, ifindex); + SignalData *address_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_address_callback, ifindex); + GArray *addresses; + NMPlatformIP4Address *address; + in_addr_t addr; + guint32 lifetime = 2000; + guint32 preferred = 1000; + + inet_pton (AF_INET, IP4_ADDRESS, &addr); + + /* Add address */ + g_assert (!nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN)); + no_error (); + g_assert (nm_platform_ip4_address_add (ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL)); + no_error (); + g_assert (nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN)); + no_error (); + accept_signal (address_added); + + /* Add address again (aka update) */ + g_assert (nm_platform_ip4_address_add (ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL)); + no_error (); + accept_signal (address_changed); + + /* Test address listing */ + addresses = nm_platform_ip4_address_get_all (ifindex); + g_assert (addresses); + no_error (); + g_assert_cmpint (addresses->len, ==, 1); + address = &g_array_index (addresses, NMPlatformIP4Address, 0); + g_assert_cmpint (address->ifindex, ==, ifindex); + g_assert_cmphex (address->address, ==, addr); + g_assert_cmpint (address->plen, ==, IP4_PLEN); + g_array_unref (addresses); + + /* Remove address */ + g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN)); + no_error (); + g_assert (!nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN)); + accept_signal (address_removed); + + /* Remove address again */ + g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN)); + no_error (); + + free_signal (address_added); + free_signal (address_changed); + free_signal (address_removed); +} + +static void +test_ip6_address (void) +{ + int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME); + SignalData *address_added = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip6_address_callback, ifindex); + SignalData *address_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip6_address_callback, ifindex); + SignalData *address_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip6_address_callback, ifindex); + GArray *addresses; + NMPlatformIP6Address *address; + struct in6_addr addr; + guint32 lifetime = 2000; + guint32 preferred = 1000; + guint flags = 0; + + inet_pton (AF_INET6, IP6_ADDRESS, &addr); + + /* Add address */ + g_assert (!nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN)); + no_error (); + g_assert (nm_platform_ip6_address_add (ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags)); + no_error (); + g_assert (nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN)); + no_error (); + accept_signal (address_added); + + /* Add address again (aka update) */ + g_assert (nm_platform_ip6_address_add (ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags)); + no_error (); + accept_signal (address_changed); + + /* Test address listing */ + addresses = nm_platform_ip6_address_get_all (ifindex); + g_assert (addresses); + no_error (); + g_assert_cmpint (addresses->len, ==, 1); + address = &g_array_index (addresses, NMPlatformIP6Address, 0); + g_assert_cmpint (address->ifindex, ==, ifindex); + g_assert (!memcmp (&address->address, &addr, sizeof (addr))); + g_assert_cmpint (address->plen, ==, IP6_PLEN); + g_array_unref (addresses); + + /* Remove address */ + g_assert (nm_platform_ip6_address_delete (ifindex, addr, IP6_PLEN)); + no_error (); + g_assert (!nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN)); + accept_signal (address_removed); + + /* Remove address again */ + g_assert (nm_platform_ip6_address_delete (ifindex, addr, IP6_PLEN)); + no_error (); + + free_signal (address_added); + free_signal (address_changed); + free_signal (address_removed); +} + +static void +test_ip4_address_external (void) +{ + SignalData *address_added = add_signal (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_address_callback); + SignalData *address_removed = add_signal (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_address_callback); + int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME); + in_addr_t addr; + guint32 lifetime = 2000; + guint32 preferred = 1000; + + inet_pton (AF_INET, IP4_ADDRESS, &addr); + g_assert (ifindex > 0); + + /* Looks like addresses are not announced by kerenl when the interface + * is down. Link-local IPv6 address is automatically added. + */ + g_assert (nm_platform_link_set_up (nm_platform_link_get_ifindex (DEVICE_NAME))); + + /* Add/delete notification */ + run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d", + IP4_ADDRESS, IP4_PLEN, DEVICE_NAME, lifetime, preferred); + wait_signal (address_added); + g_assert (nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN)); + run_command ("ip address delete %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME); + wait_signal (address_removed); + g_assert (!nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN)); + + /* Add/delete conflict */ + run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d", + IP4_ADDRESS, IP4_PLEN, DEVICE_NAME, lifetime, preferred); + g_assert (nm_platform_ip4_address_add (ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL)); + no_error (); + g_assert (nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN)); + accept_signal (address_added); + /*run_command ("ip address delete %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME); + g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN)); + no_error (); + g_assert (!nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN)); + accept_signal (address_removed);*/ + + free_signal (address_added); + free_signal (address_removed); +} + +static void +test_ip6_address_external (void) +{ + SignalData *address_added = add_signal (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip6_address_callback); + SignalData *address_removed = add_signal (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip6_address_callback); + int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME); + struct in6_addr addr; + guint32 lifetime = 2000; + guint32 preferred = 1000; + guint flags = 0; + + inet_pton (AF_INET6, IP6_ADDRESS, &addr); + + /* Add/delete notification */ + run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d", + IP6_ADDRESS, IP6_PLEN, DEVICE_NAME, lifetime, preferred); + wait_signal (address_added); + g_assert (nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN)); + run_command ("ip address delete %s/%d dev %s", IP6_ADDRESS, IP6_PLEN, DEVICE_NAME); + wait_signal (address_removed); + g_assert (!nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN)); + + /* Add/delete conflict */ + run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d", + IP6_ADDRESS, IP6_PLEN, DEVICE_NAME, lifetime, preferred); + g_assert (nm_platform_ip6_address_add (ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags)); + no_error (); + g_assert (nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN)); + accept_signal (address_added); + /*run_command ("ip address delete %s/%d dev %s", IP6_ADDRESS, IP6_PLEN, DEVICE_NAME); + g_assert (nm_platform_ip6_address_delete (ifindex, addr, IP6_PLEN)); + no_error (); + g_assert (!nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN)); + wait_signal (address_removed);*/ + + free_signal (address_added); + free_signal (address_removed); +} + +void +setup_tests (void) +{ + SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME); + + nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME)); + g_assert (!nm_platform_link_exists (DEVICE_NAME)); + g_assert (nm_platform_dummy_add (DEVICE_NAME)); + accept_signal (link_added); + free_signal (link_added); + + g_test_add_func ("/address/internal/ip4", test_ip4_address); + g_test_add_func ("/address/internal/ip6", test_ip6_address); + + if (strcmp (g_type_name (G_TYPE_FROM_INSTANCE (nm_platform_get ())), "NMFakePlatform")) { + g_test_add_func ("/address/external/ip4", test_ip4_address_external); + g_test_add_func ("/address/external/ip6", test_ip6_address_external); + } +} diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c new file mode 100644 index 00000000..e60d82f0 --- /dev/null +++ b/src/platform/tests/test-cleanup.c @@ -0,0 +1,95 @@ +#include "test-common.h" + +#define DEVICE_NAME "nm-test-device" + +static void +test_cleanup_internal () +{ + SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME); + int ifindex; + GArray *addresses4; + GArray *addresses6; + GArray *routes4; + GArray *routes6; + in_addr_t addr4; + in_addr_t network4; + int plen4 = 24; + in_addr_t gateway4; + struct in6_addr addr6; + struct in6_addr network6; + int plen6 = 64; + struct in6_addr gateway6; + int lifetime = NM_PLATFORM_LIFETIME_PERMANENT; + int preferred = NM_PLATFORM_LIFETIME_PERMANENT; + int metric = 20; + int mss = 1000; + guint flags = 0; + + inet_pton (AF_INET, "192.0.2.1", &addr4); + inet_pton (AF_INET, "192.0.3.0", &network4); + inet_pton (AF_INET, "198.51.100.1", &gateway4); + inet_pton (AF_INET6, "2001:db8:a:b:1:2:3:4", &addr6); + inet_pton (AF_INET6, "2001:db8:c:d:0:0:0:0", &network6); + inet_pton (AF_INET6, "2001:db8:e:f:1:2:3:4", &gateway6); + + /* Create and set up device */ + g_assert (nm_platform_dummy_add (DEVICE_NAME)); + accept_signal (link_added); + free_signal (link_added); + g_assert (nm_platform_link_set_up (nm_platform_link_get_ifindex (DEVICE_NAME))); + ifindex = nm_platform_link_get_ifindex (DEVICE_NAME); + g_assert (ifindex > 0); + + /* Add routes and addresses */ + g_assert (nm_platform_ip4_address_add (ifindex, addr4, 0, plen4, lifetime, preferred, NULL)); + g_assert (nm_platform_ip6_address_add (ifindex, addr6, in6addr_any, plen6, lifetime, preferred, flags)); + g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, gateway4, 32, INADDR_ANY, metric, mss)); + g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, network4, plen4, gateway4, metric, mss)); + g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, 0, 0, gateway4, metric, mss)); + g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, gateway6, 128, in6addr_any, metric, mss)); + g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, network6, plen6, gateway6, metric, mss)); + g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, in6addr_any, 0, gateway6, metric, mss)); + + addresses4 = nm_platform_ip4_address_get_all (ifindex); + addresses6 = nm_platform_ip6_address_get_all (ifindex); + routes4 = nm_platform_ip4_route_get_all (ifindex, TRUE); + routes6 = nm_platform_ip6_route_get_all (ifindex, TRUE); + + g_assert_cmpint (addresses4->len, ==, 1); + g_assert_cmpint (addresses6->len, ==, 1); + g_assert_cmpint (routes4->len, ==, 3); + g_assert_cmpint (routes6->len, ==, 3); + + g_array_unref (addresses4); + g_array_unref (addresses6); + g_array_unref (routes4); + g_array_unref (routes6); + + /* Delete interface with all addresses and routes */ + g_assert (nm_platform_link_delete (ifindex)); + + addresses4 = nm_platform_ip4_address_get_all (ifindex); + addresses6 = nm_platform_ip6_address_get_all (ifindex); + routes4 = nm_platform_ip4_route_get_all (ifindex, TRUE); + routes6 = nm_platform_ip6_route_get_all (ifindex, TRUE); + + g_assert_cmpint (addresses4->len, ==, 0); + g_assert_cmpint (addresses6->len, ==, 0); + g_assert_cmpint (routes4->len, ==, 0); + g_assert_cmpint (routes6->len, ==, 0); + + g_array_unref (addresses4); + g_array_unref (addresses6); + g_array_unref (routes4); + g_array_unref (routes6); +} + +void +setup_tests (void) +{ + nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME)); + g_assert (!nm_platform_link_exists (DEVICE_NAME)); + + g_test_add_func ("/internal", test_cleanup_internal); + /* FIXME: add external cleanup check */ +} diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c new file mode 100644 index 00000000..59a770c6 --- /dev/null +++ b/src/platform/tests/test-common.c @@ -0,0 +1,174 @@ +#include "test-common.h" + +#include "nm-test-utils.h" + +SignalData * +add_signal_full (const char *name, NMPlatformSignalChangeType change_type, GCallback callback, int ifindex, const char *ifname) +{ + SignalData *data = g_new0 (SignalData, 1); + + data->name = name; + data->change_type = change_type; + data->received = FALSE; + data->handler_id = g_signal_connect (nm_platform_get (), name, callback, data); + data->ifindex = ifindex; + data->ifname = ifname; + + g_assert (data->handler_id >= 0); + + return data; +} + +static const char * +_change_type_to_string (NMPlatformSignalChangeType change_type) +{ + switch (change_type) { + case NM_PLATFORM_SIGNAL_ADDED: + return "added"; + case NM_PLATFORM_SIGNAL_CHANGED: + return "changed"; + case NM_PLATFORM_SIGNAL_REMOVED: + return "removed"; + default: + g_return_val_if_reached ("UNKNOWN"); + } +} + +void +accept_signal (SignalData *data) +{ + debug ("Accepting signal '%s-%s' ifindex %d ifname %s.", data->name, _change_type_to_string (data->change_type), data->ifindex, data->ifname); + if (!data->received) + g_error ("Attemted to accept a non-received signal '%s-%s'.", data->name, _change_type_to_string (data->change_type)); + + data->received = FALSE; +} + +void +wait_signal (SignalData *data) +{ + if (data->received) + g_error ("Signal '%s' received before waiting for it.", data->name); + + data->loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (data->loop); + g_clear_pointer (&data->loop, g_main_loop_unref); + + accept_signal (data); +} + +void +free_signal (SignalData *data) +{ + if (data->received) + g_error ("Attempted to free received but not accepted signal '%s-%s'.", data->name, _change_type_to_string (data->change_type)); + + g_signal_handler_disconnect (nm_platform_get (), data->handler_id); + g_free (data); +} + +void +link_callback (NMPlatform *platform, int ifindex, NMPlatformLink *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data) +{ + + GArray *links; + NMPlatformLink *cached; + int i; + + g_assert (received); + g_assert_cmpint (received->ifindex, ==, ifindex); + g_assert (data && data->name); + g_assert_cmpstr (data->name, ==, NM_PLATFORM_SIGNAL_LINK_CHANGED); + + if (data->ifindex && data->ifindex != received->ifindex) + return; + if (data->ifname && g_strcmp0 (data->ifname, nm_platform_link_get_name (ifindex)) != 0) + return; + if (change_type != data->change_type) + return; + + if (data->loop) { + debug ("Quitting main loop."); + g_main_loop_quit (data->loop); + } + + if (data->received) + g_error ("Received signal '%s-%s' a second time.", data->name, _change_type_to_string (data->change_type)); + + debug ("Received signal '%s-%s' ifindex %d ifname '%s'.", data->name, _change_type_to_string (data->change_type), ifindex, received->name); + data->received = TRUE; + + if (change_type == NM_PLATFORM_SIGNAL_REMOVED) + g_assert (!nm_platform_link_get_name (ifindex)); + else + g_assert (nm_platform_link_get_name (ifindex)); + + /* Check the data */ + g_assert (received->ifindex > 0); + links = nm_platform_link_get_all (); + for (i = 0; i < links->len; i++) { + cached = &g_array_index (links, NMPlatformLink, i); + if (cached->ifindex == received->ifindex) { + g_assert_cmpint (nm_platform_link_cmp (cached, received), ==, 0); + g_assert (!memcmp (cached, received, sizeof (*cached))); + if (data->change_type == NM_PLATFORM_SIGNAL_REMOVED) + g_error ("Deleted link still found in the local cache."); + g_array_unref (links); + return; + } + } + g_array_unref (links); + + if (data->change_type != NM_PLATFORM_SIGNAL_REMOVED) + g_error ("Added/changed link not found in the local cache."); +} + +void +run_command (const char *format, ...) +{ + char *command; + va_list ap; + + va_start (ap, format); + command = g_strdup_vprintf (format, ap); + va_end (ap); + debug ("Running command: %s", command); + g_assert (!system (command)); + debug ("Command finished."); + g_free (command); +} + +NMTST_DEFINE(); + +int +main (int argc, char **argv) +{ + int result; + const char *program = *argv; + + nmtst_init_with_logging (&argc, &argv, NULL, "ALL"); + + if (SETUP == nm_linux_platform_setup && getuid() != 0) { + /* Try to exec as sudo, this function does not return, if a sudo-cmd is set. */ + nmtst_reexec_sudo (); + +#ifdef REQUIRE_ROOT_TESTS + g_message ("Fail test: requires root privileges (%s)", program); + return EXIT_FAILURE; +#else + g_message ("Skipping test: requires root privileges (%s)", program); + return 77; +#endif + } + + SETUP (); + + setup_tests (); + + result = g_test_run (); + + nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME)); + + nm_platform_free (); + return result; +} diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h new file mode 100644 index 00000000..8f6b3912 --- /dev/null +++ b/src/platform/tests/test-common.h @@ -0,0 +1,42 @@ +#include <stdlib.h> +#include <unistd.h> +#include <syslog.h> +#include <string.h> +#include <arpa/inet.h> + +#include "nm-logging.h" +#include "nm-platform.h" +#include "nm-fake-platform.h" +#include "nm-linux-platform.h" + +#define DEVICE_NAME "nm-test-device" + +#define debug(...) nm_log_dbg (LOGD_PLATFORM, __VA_ARGS__) + +#define error(err) g_assert (nm_platform_get_error () == err) +#define no_error() error (NM_PLATFORM_ERROR_NONE) + +typedef struct { + int handler_id; + const char *name; + NMPlatformSignalChangeType change_type; + gboolean received; + GMainLoop *loop; + int ifindex; + const char *ifname; +} SignalData; + +SignalData *add_signal_full (const char *name, NMPlatformSignalChangeType change_type, GCallback callback, int ifindex, const char *ifname); +#define add_signal(name, change_type, callback) add_signal_full (name, change_type, (GCallback) callback, 0, NULL) +#define add_signal_ifindex(name, change_type, callback, ifindex) add_signal_full (name, change_type, (GCallback) callback, ifindex, NULL) +#define add_signal_ifname(name, change_type, callback, ifname) add_signal_full (name, change_type, (GCallback) callback, 0, ifname) +void accept_signal (SignalData *data); +void wait_signal (SignalData *data); +void free_signal (SignalData *data); + +void link_callback (NMPlatform *platform, int ifindex, NMPlatformLink *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data); + +void run_command (const char *format, ...); + +void setup_tests (void); + diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c new file mode 100644 index 00000000..a3f757c2 --- /dev/null +++ b/src/platform/tests/test-link.c @@ -0,0 +1,557 @@ +#include "test-common.h" +#include "nm-test-utils.h" + +#define LO_INDEX 1 +#define LO_NAME "lo" +#define LO_TYPEDESC "loopback" + +#define DUMMY_TYPEDESC "dummy" +#define BOGUS_NAME "nm-bogus-device" +#define BOGUS_IFINDEX INT_MAX +#define SLAVE_NAME "nm-test-slave" +#define PARENT_NAME "nm-test-parent" +#define VLAN_ID 4077 +#define VLAN_FLAGS 0 +#define MTU 1357 + +static void +test_bogus(void) +{ + size_t addrlen; + + g_assert (!nm_platform_link_exists (BOGUS_NAME)); + no_error (); + g_assert (!nm_platform_link_delete (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_get_ifindex (BOGUS_NAME)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_get_name (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_get_type (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_get_type_name (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + + g_assert (!nm_platform_link_set_up (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_set_down (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_set_arp (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_set_noarp (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_is_up (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_is_connected (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_uses_arp (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + + g_assert (!nm_platform_link_get_address (BOGUS_IFINDEX, &addrlen)); + g_assert (!addrlen); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_get_address (BOGUS_IFINDEX, NULL)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_set_mtu (BOGUS_IFINDEX, MTU)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_get_mtu (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + + g_assert (!nm_platform_link_supports_carrier_detect (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_supports_vlans (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + + g_assert (!nm_platform_vlan_get_info (BOGUS_IFINDEX, NULL, NULL)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_vlan_set_ingress_map (BOGUS_IFINDEX, 0, 0)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_vlan_set_egress_map (BOGUS_IFINDEX, 0, 0)); + error (NM_PLATFORM_ERROR_NOT_FOUND); +} + +static void +test_loopback (void) +{ + g_assert (nm_platform_link_exists (LO_NAME)); + g_assert_cmpint (nm_platform_link_get_type (LO_INDEX), ==, NM_LINK_TYPE_LOOPBACK); + g_assert_cmpint (nm_platform_link_get_ifindex (LO_NAME), ==, LO_INDEX); + g_assert_cmpstr (nm_platform_link_get_name (LO_INDEX), ==, LO_NAME); + g_assert_cmpstr (nm_platform_link_get_type_name (LO_INDEX), ==, LO_TYPEDESC); + + g_assert (nm_platform_link_supports_carrier_detect (LO_INDEX)); + g_assert (!nm_platform_link_supports_vlans (LO_INDEX)); +} + +static int +software_add (NMLinkType link_type, const char *name) +{ + switch (link_type) { + case NM_LINK_TYPE_DUMMY: + return nm_platform_dummy_add (name); + case NM_LINK_TYPE_BRIDGE: + return nm_platform_bridge_add (name, NULL, 0); + case NM_LINK_TYPE_BOND: + { + gboolean bond0_exists = nm_platform_link_exists ("bond0"); + gboolean result = nm_platform_bond_add (name); + NMPlatformError error = nm_platform_get_error (); + + /* Check that bond0 is *not* automatically created. */ + if (!bond0_exists) + g_assert (!nm_platform_link_exists ("bond0")); + + nm_platform_set_error (error); + return result; + } + case NM_LINK_TYPE_TEAM: + return nm_platform_team_add (name); + case NM_LINK_TYPE_VLAN: { + SignalData *parent_added; + SignalData *parent_changed; + + /* Don't call link_callback for the bridge interface */ + parent_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, PARENT_NAME); + if (nm_platform_bridge_add (PARENT_NAME, NULL, 0)) + accept_signal (parent_added); + free_signal (parent_added); + + { + int parent_ifindex = nm_platform_link_get_ifindex (PARENT_NAME); + + parent_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, parent_ifindex); + g_assert (nm_platform_link_set_up (parent_ifindex)); + accept_signal (parent_changed); + free_signal (parent_changed); + + return nm_platform_vlan_add (name, parent_ifindex, VLAN_ID, 0); + } + } + default: + g_error ("Link type %d unhandled.", link_type); + } +} + +static void +test_slave (int master, int type, SignalData *master_changed) +{ + int ifindex; + SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, SLAVE_NAME); + SignalData *link_changed, *link_removed; + char *value; + + g_assert (software_add (type, SLAVE_NAME)); + ifindex = nm_platform_link_get_ifindex (SLAVE_NAME); + g_assert (ifindex > 0); + link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex); + link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex); + accept_signal (link_added); + + /* Set the slave up to see whether master's IFF_LOWER_UP is set correctly. + * + * See https://bugzilla.redhat.com/show_bug.cgi?id=910348 + */ + g_assert (nm_platform_link_set_down (ifindex)); + g_assert (!nm_platform_link_is_up (ifindex)); + accept_signal (link_changed); + + /* Enslave */ + link_changed->ifindex = ifindex; + g_assert (nm_platform_link_enslave (master, ifindex)); no_error (); + g_assert_cmpint (nm_platform_link_get_master (ifindex), ==, master); no_error (); + accept_signal (link_changed); + accept_signal (master_changed); + + /* Set master up */ + g_assert (nm_platform_link_set_up (master)); + accept_signal (master_changed); + + /* Master with a disconnected slave is disconnected + * + * For some reason, bonding and teaming slaves are automatically set up. We + * need to set them back down for this test. + */ + switch (nm_platform_link_get_type (master)) { + case NM_LINK_TYPE_BOND: + case NM_LINK_TYPE_TEAM: + g_assert (nm_platform_link_set_down (ifindex)); + accept_signal (link_changed); + accept_signal (master_changed); + break; + default: + break; + } + g_assert (!nm_platform_link_is_up (ifindex)); + g_assert (!nm_platform_link_is_connected (ifindex)); + if (nm_platform_link_is_connected (master)) { + if (nm_platform_link_get_type (master) == NM_LINK_TYPE_TEAM) { + /* Older team versions (e.g. Fedora 17) have a bug that team master stays + * IFF_LOWER_UP even if its slave is down. Double check it with iproute2 and if + * `ip link` also claims master to be up, accept it. */ + char *stdout = NULL; + + nmtst_spawn_sync (NULL, &stdout, NULL, 0, "/sbin/ip", "link", "show", "dev", nm_platform_link_get_name (master)); + + g_assert (strstr (stdout, "LOWER_UP")); + g_free (stdout); + } else + g_assert_not_reached (); + } + + /* Set slave up and see if master gets up too */ + g_assert (nm_platform_link_set_up (ifindex)); no_error (); + g_assert (nm_platform_link_is_connected (ifindex)); + g_assert (nm_platform_link_is_connected (master)); + accept_signal (link_changed); + accept_signal (master_changed); + + /* Enslave again + * + * Gracefully succeed if already enslaved. + */ + g_assert (nm_platform_link_enslave (master, ifindex)); no_error (); + accept_signal (link_changed); + accept_signal (master_changed); + + /* Set slave option */ + switch (type) { + case NM_LINK_TYPE_BRIDGE: + g_assert (nm_platform_slave_set_option (ifindex, "priority", "789")); + no_error (); + value = nm_platform_slave_get_option (ifindex, "priority"); + no_error (); + g_assert_cmpstr (value, ==, "789"); + g_free (value); + break; + default: + break; + } + + /* Release */ + g_assert (nm_platform_link_release (master, ifindex)); + g_assert_cmpint (nm_platform_link_get_master (ifindex), ==, 0); no_error (); + accept_signal (link_changed); + accept_signal (master_changed); + + /* Release again */ + g_assert (!nm_platform_link_release (master, ifindex)); + error (NM_PLATFORM_ERROR_NOT_SLAVE); + + /* Remove */ + g_assert (nm_platform_link_delete (ifindex)); + no_error (); + accept_signal (link_removed); + + free_signal (link_added); + free_signal (link_changed); + free_signal (link_removed); +} + +static void +test_software (NMLinkType link_type, const char *link_typename) +{ + int ifindex; + char *value; + int vlan_parent, vlan_id; + + SignalData *link_added, *link_changed, *link_removed; + + /* Add */ + link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME); + g_assert (software_add (link_type, DEVICE_NAME)); + no_error (); + accept_signal (link_added); + g_assert (nm_platform_link_exists (DEVICE_NAME)); + ifindex = nm_platform_link_get_ifindex (DEVICE_NAME); + g_assert (ifindex >= 0); + g_assert_cmpint (nm_platform_link_get_type (ifindex), ==, link_type); + g_assert_cmpstr (nm_platform_link_get_type_name (ifindex), ==, link_typename); + link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex); + link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex); + if (link_type == NM_LINK_TYPE_VLAN) { + g_assert (nm_platform_vlan_get_info (ifindex, &vlan_parent, &vlan_id)); + g_assert_cmpint (vlan_parent, ==, nm_platform_link_get_ifindex (PARENT_NAME)); + g_assert_cmpint (vlan_id, ==, VLAN_ID); + no_error (); + } + + /* Add again */ + g_assert (!software_add (link_type, DEVICE_NAME)); + error (NM_PLATFORM_ERROR_EXISTS); + + /* Set ARP/NOARP */ + g_assert (nm_platform_link_uses_arp (ifindex)); + g_assert (nm_platform_link_set_noarp (ifindex)); + g_assert (!nm_platform_link_uses_arp (ifindex)); + accept_signal (link_changed); + g_assert (nm_platform_link_set_arp (ifindex)); + g_assert (nm_platform_link_uses_arp (ifindex)); + accept_signal (link_changed); + + /* Set master option */ + switch (link_type) { + case NM_LINK_TYPE_BRIDGE: + g_assert (nm_platform_master_set_option (ifindex, "forward_delay", "789")); + no_error (); + value = nm_platform_master_get_option (ifindex, "forward_delay"); + no_error (); + g_assert_cmpstr (value, ==, "789"); + g_free (value); + break; + case NM_LINK_TYPE_BOND: + g_assert (nm_platform_master_set_option (ifindex, "mode", "active-backup")); + no_error (); + value = nm_platform_master_get_option (ifindex, "mode"); + no_error (); + /* When reading back, the output looks slightly different. */ + g_assert (g_str_has_prefix (value, "active-backup")); + g_free (value); + break; + default: + break; + } + + /* Enslave and release */ + switch (link_type) { + case NM_LINK_TYPE_BRIDGE: + case NM_LINK_TYPE_BOND: + case NM_LINK_TYPE_TEAM: + link_changed->ifindex = ifindex; + test_slave (ifindex, NM_LINK_TYPE_DUMMY, link_changed); + link_changed->ifindex = 0; + break; + default: + break; + } + + /* Delete */ + g_assert (nm_platform_link_delete (ifindex)); + no_error (); + g_assert (!nm_platform_link_exists (DEVICE_NAME)); no_error (); + g_assert_cmpint (nm_platform_link_get_type (ifindex), ==, NM_LINK_TYPE_NONE); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_get_type (ifindex)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + accept_signal (link_removed); + + /* Delete again */ + g_assert (!nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME))); + error (NM_PLATFORM_ERROR_NOT_FOUND); + + /* VLAN: Delete parent */ + if (link_type == NM_LINK_TYPE_VLAN) { + SignalData *link_removed_parent = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, vlan_parent); + + g_assert (nm_platform_link_delete (vlan_parent)); + accept_signal (link_removed_parent); + free_signal (link_removed_parent); + } + + /* No pending signal */ + free_signal (link_added); + free_signal (link_changed); + free_signal (link_removed); +} + +static void +test_bridge (void) +{ + test_software (NM_LINK_TYPE_BRIDGE, "bridge"); +} + +static void +test_bond (void) +{ + if (SETUP == nm_linux_platform_setup && + !g_file_test ("/proc/1/net/bonding", G_FILE_TEST_IS_DIR) && + system("modprobe --show bonding") != 0) { + g_test_skip ("Skipping test for bonding: bonding module not available"); + return; + } + + test_software (NM_LINK_TYPE_BOND, "bond"); +} + +static void +test_team (void) +{ + test_software (NM_LINK_TYPE_TEAM, "team"); +} + +static void +test_vlan () +{ + test_software (NM_LINK_TYPE_VLAN, "vlan"); +} + +static void +test_internal (void) +{ + SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME); + SignalData *link_changed, *link_removed; + const char mac[6] = { 0x00, 0xff, 0x11, 0xee, 0x22, 0xdd }; + const char *address; + size_t addrlen; + int ifindex; + + /* Check the functions for non-existent devices */ + g_assert (!nm_platform_link_exists (DEVICE_NAME)); no_error (); + g_assert (!nm_platform_link_get_ifindex (DEVICE_NAME)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + + /* Add device */ + g_assert (nm_platform_dummy_add (DEVICE_NAME)); + no_error (); + accept_signal (link_added); + + /* Try to add again */ + g_assert (!nm_platform_dummy_add (DEVICE_NAME)); + error (NM_PLATFORM_ERROR_EXISTS); + + /* Check device index, name and type */ + ifindex = nm_platform_link_get_ifindex (DEVICE_NAME); + g_assert (ifindex > 0); + g_assert_cmpstr (nm_platform_link_get_name (ifindex), ==, DEVICE_NAME); + g_assert_cmpint (nm_platform_link_get_type (ifindex), ==, NM_LINK_TYPE_DUMMY); + g_assert_cmpstr (nm_platform_link_get_type_name (ifindex), ==, DUMMY_TYPEDESC); + link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex); + link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex); + + /* Up/connected */ + g_assert (!nm_platform_link_is_up (ifindex)); no_error (); + g_assert (!nm_platform_link_is_connected (ifindex)); no_error (); + g_assert (nm_platform_link_set_up (ifindex)); no_error (); + g_assert (nm_platform_link_is_up (ifindex)); no_error (); + g_assert (nm_platform_link_is_connected (ifindex)); no_error (); + accept_signal (link_changed); + g_assert (nm_platform_link_set_down (ifindex)); no_error (); + g_assert (!nm_platform_link_is_up (ifindex)); no_error (); + g_assert (!nm_platform_link_is_connected (ifindex)); no_error (); + accept_signal (link_changed); + + /* arp/noarp */ + g_assert (!nm_platform_link_uses_arp (ifindex)); + g_assert (nm_platform_link_set_arp (ifindex)); + g_assert (nm_platform_link_uses_arp (ifindex)); + accept_signal (link_changed); + g_assert (nm_platform_link_set_noarp (ifindex)); + g_assert (!nm_platform_link_uses_arp (ifindex)); + accept_signal (link_changed); + + /* Features */ + g_assert (!nm_platform_link_supports_carrier_detect (ifindex)); + g_assert (nm_platform_link_supports_vlans (ifindex)); + + /* Set MAC address */ + g_assert (nm_platform_link_set_address (ifindex, mac, sizeof (mac))); + address = nm_platform_link_get_address (ifindex, &addrlen); + g_assert (addrlen == sizeof(mac)); + g_assert (!memcmp (address, mac, addrlen)); + address = nm_platform_link_get_address (ifindex, NULL); + g_assert (!memcmp (address, mac, addrlen)); + accept_signal (link_changed); + + /* Set MTU */ + g_assert (nm_platform_link_set_mtu (ifindex, MTU)); + no_error (); + g_assert_cmpint (nm_platform_link_get_mtu (ifindex), ==, MTU); + accept_signal (link_changed); + + /* Delete device */ + g_assert (nm_platform_link_delete (ifindex)); + no_error (); + accept_signal (link_removed); + + /* Try to delete again */ + g_assert (!nm_platform_link_delete (ifindex)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + + free_signal (link_added); + free_signal (link_changed); + free_signal (link_removed); +} + +static void +test_external (void) +{ + NMPlatformLink link; + SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME); + SignalData *link_changed, *link_removed; + int ifindex; + gboolean success; + + run_command ("ip link add %s type %s", DEVICE_NAME, "dummy"); + wait_signal (link_added); + g_assert (nm_platform_link_exists (DEVICE_NAME)); + ifindex = nm_platform_link_get_ifindex (DEVICE_NAME); + g_assert (ifindex > 0); + g_assert_cmpstr (nm_platform_link_get_name (ifindex), ==, DEVICE_NAME); + g_assert_cmpint (nm_platform_link_get_type (ifindex), ==, NM_LINK_TYPE_DUMMY); + g_assert_cmpstr (nm_platform_link_get_type_name (ifindex), ==, DUMMY_TYPEDESC); + link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex); + link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex); + + success = nm_platform_link_get (ifindex, &link); + g_assert (success); + if (!link.driver) { + /* we still lack the notification via UDEV. Expect another link changed signal. */ + wait_signal (link_changed); + } + + /* Up/connected/arp */ + g_assert (!nm_platform_link_is_up (ifindex)); + g_assert (!nm_platform_link_is_connected (ifindex)); + g_assert (!nm_platform_link_uses_arp (ifindex)); + run_command ("ip link set %s up", DEVICE_NAME); + wait_signal (link_changed); + g_assert (nm_platform_link_is_up (ifindex)); + g_assert (nm_platform_link_is_connected (ifindex)); + run_command ("ip link set %s down", DEVICE_NAME); + wait_signal (link_changed); + g_assert (!nm_platform_link_is_up (ifindex)); + g_assert (!nm_platform_link_is_connected (ifindex)); + /* This test doesn't trigger a netlink event at least on + * 3.8.2-206.fc18.x86_64. Disabling the waiting and checking code + * because of that. + */ + run_command ("ip link set %s arp on", DEVICE_NAME); +#if 0 + wait_signal (link_changed); + g_assert (nm_platform_link_uses_arp (ifindex)); +#endif + run_command ("ip link set %s arp off", DEVICE_NAME); +#if 0 + wait_signal (link_changed); + g_assert (!nm_platform_link_uses_arp (ifindex)); +#endif + + run_command ("ip link del %s", DEVICE_NAME); + wait_signal (link_removed); + g_assert (!nm_platform_link_exists (DEVICE_NAME)); + + free_signal (link_added); + free_signal (link_changed); + free_signal (link_removed); +} + +void +setup_tests (void) +{ + nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME)); + nm_platform_link_delete (nm_platform_link_get_ifindex (SLAVE_NAME)); + nm_platform_link_delete (nm_platform_link_get_ifindex (PARENT_NAME)); + g_assert (!nm_platform_link_exists (DEVICE_NAME)); + g_assert (!nm_platform_link_exists (SLAVE_NAME)); + g_assert (!nm_platform_link_exists (PARENT_NAME)); + + g_test_add_func ("/link/bogus", test_bogus); + g_test_add_func ("/link/loopback", test_loopback); + g_test_add_func ("/link/internal", test_internal); + g_test_add_func ("/link/software/bridge", test_bridge); + g_test_add_func ("/link/software/bond", test_bond); + g_test_add_func ("/link/software/team", test_team); + g_test_add_func ("/link/software/vlan", test_vlan); + + if (strcmp (g_type_name (G_TYPE_FROM_INSTANCE (nm_platform_get ())), "NMFakePlatform")) + g_test_add_func ("/link/external", test_external); +} diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c new file mode 100644 index 00000000..d45730ac --- /dev/null +++ b/src/platform/tests/test-route.c @@ -0,0 +1,255 @@ +#include "test-common.h" +#include "nm-test-utils.h" + +#define DEVICE_NAME "nm-test-device" + +static void +ip4_route_callback (NMPlatform *platform, int ifindex, NMPlatformIP4Route *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data) +{ + g_assert (received); + g_assert_cmpint (received->ifindex, ==, ifindex); + g_assert (data && data->name); + g_assert_cmpstr (data->name, ==, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED); + + if (data->ifindex && data->ifindex != received->ifindex) + return; + if (data->change_type != change_type) + return; + + if (data->loop) + g_main_loop_quit (data->loop); + + if (data->received) + g_error ("Received signal '%s' a second time.", data->name); + + data->received = TRUE; +} + +static void +ip6_route_callback (NMPlatform *platform, int ifindex, NMPlatformIP6Route *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data) +{ + g_assert (received); + g_assert_cmpint (received->ifindex, ==, ifindex); + g_assert (data && data->name); + g_assert_cmpstr (data->name, ==, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED); + + if (data->ifindex && data->ifindex != received->ifindex) + return; + if (data->change_type != change_type) + return; + + if (data->loop) + g_main_loop_quit (data->loop); + + if (data->received) + g_error ("Received signal '%s' a second time.", data->name); + + data->received = TRUE; +} + +static void +test_ip4_route () +{ + int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME); + SignalData *route_added = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_route_callback); + SignalData *route_changed = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip4_route_callback); + SignalData *route_removed = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_route_callback); + GArray *routes; + NMPlatformIP4Route rts[3]; + in_addr_t network; + int plen = 24; + in_addr_t gateway; + int metric = 20; + int mss = 1000; + + inet_pton (AF_INET, "192.0.3.0", &network); + inet_pton (AF_INET, "198.51.100.1", &gateway); + + /* Add route to gateway */ + g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, gateway, 32, INADDR_ANY, metric, mss)); + no_error (); + accept_signal (route_added); + + /* Add route */ + g_assert (!nm_platform_ip4_route_exists (ifindex, network, plen, metric)); + no_error (); + g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, network, plen, gateway, metric, mss)); + no_error (); + g_assert (nm_platform_ip4_route_exists (ifindex, network, plen, metric)); + no_error (); + accept_signal (route_added); + + /* Add route again */ + g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, network, plen, gateway, metric, mss)); + no_error (); + accept_signal (route_changed); + + /* Add default route */ + g_assert (!nm_platform_ip4_route_exists (ifindex, 0, 0, metric)); + no_error (); + g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, 0, 0, gateway, metric, mss)); + no_error (); + g_assert (nm_platform_ip4_route_exists (ifindex, 0, 0, metric)); + no_error (); + accept_signal (route_added); + + /* Add default route again */ + g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, 0, 0, gateway, metric, mss)); + no_error (); + accept_signal (route_changed); + + /* Test route listing */ + routes = nm_platform_ip4_route_get_all (ifindex, TRUE); + memset (rts, 0, sizeof (rts)); + rts[0].source = NM_PLATFORM_SOURCE_USER; + rts[0].network = gateway; + rts[0].plen = 32; + rts[0].ifindex = ifindex; + rts[0].gateway = INADDR_ANY; + rts[0].metric = metric; + rts[0].mss = mss; + rts[1].source = NM_PLATFORM_SOURCE_USER; + rts[1].network = network; + rts[1].plen = plen; + rts[1].ifindex = ifindex; + rts[1].gateway = gateway; + rts[1].metric = metric; + rts[1].mss = mss; + rts[2].source = NM_PLATFORM_SOURCE_USER; + rts[2].network = 0; + rts[2].plen = 0; + rts[2].ifindex = ifindex; + rts[2].gateway = gateway; + rts[2].metric = metric; + rts[2].mss = mss; + g_assert_cmpint (routes->len, ==, 3); + g_assert (!memcmp (routes->data, rts, sizeof (rts))); + nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, rts, routes->len); + g_array_unref (routes); + + /* Remove route */ + g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, metric)); + no_error (); + g_assert (!nm_platform_ip4_route_exists (ifindex, network, plen, metric)); + accept_signal (route_removed); + + /* Remove route again */ + g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, metric)); + no_error (); + + free_signal (route_added); + free_signal (route_changed); + free_signal (route_removed); +} + +static void +test_ip6_route () +{ + int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME); + SignalData *route_added = add_signal (NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip6_route_callback); + SignalData *route_changed = add_signal (NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip6_route_callback); + SignalData *route_removed = add_signal (NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip6_route_callback); + GArray *routes; + NMPlatformIP6Route rts[3]; + struct in6_addr network; + int plen = 64; + struct in6_addr gateway; + int metric = 20; + int mss = 1000; + + inet_pton (AF_INET6, "2001:db8:a:b:0:0:0:0", &network); + inet_pton (AF_INET6, "2001:db8:c:d:1:2:3:4", &gateway); + + /* Add route to gateway */ + g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, gateway, 128, in6addr_any, metric, mss)); + no_error (); + accept_signal (route_added); + + /* Add route */ + g_assert (!nm_platform_ip6_route_exists (ifindex, network, plen, metric)); + no_error (); + g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, network, plen, gateway, metric, mss)); + no_error (); + g_assert (nm_platform_ip6_route_exists (ifindex, network, plen, metric)); + no_error (); + accept_signal (route_added); + + /* Add route again */ + g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, network, plen, gateway, metric, mss)); + no_error (); + accept_signal (route_changed); + + /* Add default route */ + g_assert (!nm_platform_ip6_route_exists (ifindex, in6addr_any, 0, metric)); + no_error (); + g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, in6addr_any, 0, gateway, metric, mss)); + no_error (); + g_assert (nm_platform_ip6_route_exists (ifindex, in6addr_any, 0, metric)); + no_error (); + accept_signal (route_added); + + /* Add default route again */ + g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, in6addr_any, 0, gateway, metric, mss)); + no_error (); + accept_signal (route_changed); + + /* Test route listing */ + routes = nm_platform_ip6_route_get_all (ifindex, TRUE); + memset (rts, 0, sizeof (rts)); + rts[0].source = NM_PLATFORM_SOURCE_USER; + rts[0].network = gateway; + rts[0].plen = 128; + rts[0].ifindex = ifindex; + rts[0].gateway = in6addr_any; + rts[0].metric = metric; + rts[0].mss = mss; + rts[1].source = NM_PLATFORM_SOURCE_USER; + rts[1].network = network; + rts[1].plen = plen; + rts[1].ifindex = ifindex; + rts[1].gateway = gateway; + rts[1].metric = metric; + rts[1].mss = mss; + rts[2].source = NM_PLATFORM_SOURCE_USER; + rts[2].network = in6addr_any; + rts[2].plen = 0; + rts[2].ifindex = ifindex; + rts[2].gateway = gateway; + rts[2].metric = metric; + rts[2].mss = mss; + g_assert_cmpint (routes->len, ==, 3); + g_assert (!memcmp (routes->data, rts, sizeof (rts))); + nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, rts, routes->len); + g_array_unref (routes); + + /* Remove route */ + g_assert (nm_platform_ip6_route_delete (ifindex, network, plen, metric)); + no_error (); + g_assert (!nm_platform_ip6_route_exists (ifindex, network, plen, metric)); + accept_signal (route_removed); + + /* Remove route again */ + g_assert (nm_platform_ip6_route_delete (ifindex, network, plen, metric)); + no_error (); + + free_signal (route_added); + free_signal (route_changed); + free_signal (route_removed); +} + +void +setup_tests (void) +{ + SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME); + + nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME)); + g_assert (!nm_platform_link_exists (DEVICE_NAME)); + g_assert (nm_platform_dummy_add (DEVICE_NAME)); + accept_signal (link_added); + free_signal (link_added); + + g_assert (nm_platform_link_set_up (nm_platform_link_get_ifindex (DEVICE_NAME))); + + g_test_add_func ("/route/ip4", test_ip4_route); + g_test_add_func ("/route/ip6", test_ip6_route); +} diff --git a/src/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c new file mode 100644 index 00000000..25ebd1b3 --- /dev/null +++ b/src/platform/wifi/wifi-utils-nl80211.c @@ -0,0 +1,971 @@ +/* -*- 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) 2005 - 2011 Red Hat, Inc. + * Copyright (C) 2006 - 2008 Novell, Inc. + * Copyright (C) 2011 Intel Corporation. All rights reserved. + */ + +#include <config.h> +#include <errno.h> +#include <string.h> +#include <sys/ioctl.h> +#include <net/ethernet.h> +#include <unistd.h> +#include <math.h> + +#include <glib.h> + +#include <netlink/genl/genl.h> +#include <netlink/genl/family.h> +#include <netlink/genl/ctrl.h> + +#include <linux/nl80211.h> + +#include "wifi-utils-private.h" +#include "wifi-utils-nl80211.h" +#include "nm-platform.h" +#include "nm-logging.h" +#include "nm-utils.h" + +typedef struct { + WifiData parent; + struct nl_sock *nl_sock; + int id; + struct nl_cb *nl_cb; + guint32 *freqs; + int num_freqs; + int phy; +} WifiDataNl80211; + +static int +ack_handler (struct nl_msg *msg, void *arg) +{ + int *done = arg; + *done = 1; + return NL_STOP; +} + +static int +finish_handler (struct nl_msg *msg, void *arg) +{ + int *done = arg; + *done = 1; + return NL_SKIP; +} + +static int +error_handler (struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) +{ + int *done = arg; + *done = err->error; + return NL_SKIP; +} + +static struct nl_msg * +_nl80211_alloc_msg (int id, int ifindex, int phy, guint32 cmd, guint32 flags) +{ + struct nl_msg *msg; + + msg = nlmsg_alloc (); + if (msg) { + genlmsg_put (msg, 0, 0, id, 0, flags, cmd, 0); + NLA_PUT_U32 (msg, NL80211_ATTR_IFINDEX, ifindex); + if (phy != -1) + NLA_PUT_U32 (msg, NL80211_ATTR_WIPHY, phy); + } + return msg; + + nla_put_failure: + nlmsg_free (msg); + return NULL; +} + +static struct nl_msg * +nl80211_alloc_msg (WifiDataNl80211 *nl80211, guint32 cmd, guint32 flags) +{ + return _nl80211_alloc_msg (nl80211->id, nl80211->parent.ifindex, nl80211->phy, cmd, flags); +} + +/* NOTE: this function consumes 'msg' */ +static int +_nl80211_send_and_recv (struct nl_sock *nl_sock, + struct nl_cb *nl_cb, + struct nl_msg *msg, + int (*valid_handler) (struct nl_msg *, void *), + void *valid_data) +{ + struct nl_cb *cb; + int err, done; + + g_return_val_if_fail (msg != NULL, -ENOMEM); + + cb = nl_cb_clone (nl_cb); + if (!cb) { + err = -ENOMEM; + goto out; + } + + err = nl_send_auto_complete (nl_sock, msg); + if (err < 0) + goto out; + + done = 0; + nl_cb_err (cb, NL_CB_CUSTOM, error_handler, &done); + nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &done); + nl_cb_set (cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &done); + if (valid_handler) + nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, valid_data); + + /* Loop until one of our NL callbacks says we're done; on success + * done will be 1, on error it will be < 0. + */ + while (!done) { + err = nl_recvmsgs (nl_sock, cb); + if (err && err != -NLE_AGAIN) { + /* Kernel scan list can change while we are dumping it, as new scan + * results from H/W can arrive. BSS info is assured to be consistent + * and we don't need consistent view of whole scan list. Hence do + * not warn on DUMP_INTR error for get scan command. + */ + if (err == -NLE_DUMP_INTR && + genlmsg_hdr(nlmsg_hdr(msg))->cmd == NL80211_CMD_GET_SCAN) + break; + + nm_log_warn (LOGD_WIFI, "nl_recvmsgs() error: (%d) %s", + err, nl_geterror (err)); + break; + } + } + if (err == 0 && done < 0) + err = done; + + out: + nl_cb_put (cb); + nlmsg_free (msg); + return err; +} + +static int +nl80211_send_and_recv (WifiDataNl80211 *nl80211, + struct nl_msg *msg, + int (*valid_handler) (struct nl_msg *, void *), + void *valid_data) +{ + return _nl80211_send_and_recv (nl80211->nl_sock, nl80211->nl_cb, msg, + valid_handler, valid_data); +} + +static void +wifi_nl80211_deinit (WifiData *parent) +{ + WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) parent; + + if (nl80211->nl_sock) + nl_socket_free (nl80211->nl_sock); + if (nl80211->nl_cb) + nl_cb_put (nl80211->nl_cb); + g_free (nl80211->freqs); +} + +struct nl80211_iface_info { + NM80211Mode mode; +}; + +static int +nl80211_iface_info_handler (struct nl_msg *msg, void *arg) +{ + struct nl80211_iface_info *info = arg; + struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + + if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), + genlmsg_attrlen (gnlh, 0), NULL) < 0) + return NL_SKIP; + + if (!tb[NL80211_ATTR_IFTYPE]) + return NL_SKIP; + + switch (nla_get_u32 (tb[NL80211_ATTR_IFTYPE])) { + case NL80211_IFTYPE_ADHOC: + info->mode = NM_802_11_MODE_ADHOC; + break; + case NL80211_IFTYPE_AP: + info->mode = NM_802_11_MODE_AP; + break; + case NL80211_IFTYPE_STATION: + info->mode = NM_802_11_MODE_INFRA; + break; + } + + return NL_SKIP; +} + +static NM80211Mode +wifi_nl80211_get_mode (WifiData *data) +{ + WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + struct nl80211_iface_info iface_info = { + .mode = NM_802_11_MODE_UNKNOWN, + }; + struct nl_msg *msg; + + msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_INTERFACE, 0); + + if (nl80211_send_and_recv (nl80211, msg, nl80211_iface_info_handler, + &iface_info) < 0) + return NM_802_11_MODE_UNKNOWN; + + return iface_info.mode; +} + +static gboolean +wifi_nl80211_set_mode (WifiData *data, const NM80211Mode mode) +{ + WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + struct nl_msg *msg; + int err; + + msg = nl80211_alloc_msg (nl80211, NL80211_CMD_SET_INTERFACE, 0); + + switch (mode) { + case NM_802_11_MODE_INFRA: + NLA_PUT_U32 (msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_STATION); + break; + case NM_802_11_MODE_ADHOC: + NLA_PUT_U32 (msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_ADHOC); + break; + case NM_802_11_MODE_AP: + NLA_PUT_U32 (msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP); + break; + default: + g_assert_not_reached (); + } + + err = nl80211_send_and_recv (nl80211, msg, NULL, NULL); + return err ? FALSE : TRUE; + + nla_put_failure: + nlmsg_free (msg); + return FALSE; +} + +/* @divisor: pass what value @xbm should be divided by to get dBm */ +static guint32 +nl80211_xbm_to_percent (gint32 xbm, guint32 divisor) +{ +#define NOISE_FLOOR_DBM -90 +#define SIGNAL_MAX_DBM -20 + + xbm /= divisor; + xbm = CLAMP(xbm, NOISE_FLOOR_DBM, SIGNAL_MAX_DBM); + + return 100 - 70 * (((float) SIGNAL_MAX_DBM - (float) xbm) / + ((float) SIGNAL_MAX_DBM - (float) NOISE_FLOOR_DBM)); +} + +struct nl80211_bss_info { + guint32 freq; + guint8 bssid[ETH_ALEN]; + guint8 ssid[32]; + guint32 ssid_len; + guint32 beacon_signal; + gboolean valid; +}; + +#define WLAN_EID_SSID 0 + +static void +find_ssid (guint8 *ies, guint32 ies_len, + guint8 **ssid, guint32 *ssid_len) +{ + *ssid = NULL; + *ssid_len = 0; + + while (ies_len > 2 && ies[0] != WLAN_EID_SSID) { + ies_len -= ies[1] + 2; + ies += ies[1] + 2; + } + if (ies_len < 2) + return; + if (ies_len < 2 + ies[1]) + return; + + *ssid_len = ies[1]; + *ssid = ies + 2; +} + +static int +nl80211_bss_dump_handler (struct nl_msg *msg, void *arg) +{ + struct nl80211_bss_info *info = arg; + struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct nlattr *bss[NL80211_BSS_MAX + 1]; + static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { + [NL80211_BSS_TSF] = { .type = NLA_U64 }, + [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, + [NL80211_BSS_BSSID] = { }, + [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, + [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, + [NL80211_BSS_INFORMATION_ELEMENTS] = { }, + [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, + [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, + [NL80211_BSS_STATUS] = { .type = NLA_U32 }, + }; + guint32 status; + + if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), + genlmsg_attrlen (gnlh, 0), NULL) < 0) + return NL_SKIP; + + if (tb[NL80211_ATTR_BSS] == NULL) + return NL_SKIP; + + if (nla_parse_nested (bss, NL80211_BSS_MAX, + tb[NL80211_ATTR_BSS], + bss_policy)) + return NL_SKIP; + + if (bss[NL80211_BSS_STATUS] == NULL) + return NL_SKIP; + + status = nla_get_u32 (bss[NL80211_BSS_STATUS]); + + if (status != NL80211_BSS_STATUS_ASSOCIATED && + status != NL80211_BSS_STATUS_IBSS_JOINED) + return NL_SKIP; + + if (bss[NL80211_BSS_BSSID] == NULL) + return NL_SKIP; + memcpy(info->bssid, nla_data (bss[NL80211_BSS_BSSID]), ETH_ALEN); + + if (bss[NL80211_BSS_FREQUENCY]) + info->freq = nla_get_u32 (bss[NL80211_BSS_FREQUENCY]); + + if (bss[NL80211_BSS_SIGNAL_UNSPEC]) + info->beacon_signal = + nla_get_u8 (bss[NL80211_BSS_SIGNAL_UNSPEC]); + + if (bss[NL80211_BSS_SIGNAL_MBM]) + info->beacon_signal = + nl80211_xbm_to_percent (nla_get_u32 (bss[NL80211_BSS_SIGNAL_MBM]), 100); + + if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) { + guint8 *ssid; + guint32 ssid_len; + + find_ssid(nla_data (bss[NL80211_BSS_INFORMATION_ELEMENTS]), + nla_len (bss[NL80211_BSS_INFORMATION_ELEMENTS]), + &ssid, &ssid_len); + if (ssid && ssid_len && ssid_len <= sizeof (info->ssid)) { + memcpy (info->ssid, ssid, ssid_len); + info->ssid_len = ssid_len; + } + } + + info->valid = TRUE; + + return NL_SKIP; +} + +static void +nl80211_get_bss_info (WifiDataNl80211 *nl80211, + struct nl80211_bss_info *bss_info) +{ + struct nl_msg *msg; + + memset(bss_info, 0, sizeof (*bss_info)); + + msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_SCAN, NLM_F_DUMP); + + nl80211_send_and_recv (nl80211, msg, nl80211_bss_dump_handler, bss_info); +} + +static guint32 +wifi_nl80211_get_freq (WifiData *data) +{ + WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + struct nl80211_bss_info bss_info; + + nl80211_get_bss_info (nl80211, &bss_info); + + return bss_info.freq; +} + +static guint32 +wifi_nl80211_find_freq (WifiData *data, const guint32 *freqs) +{ + WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + int i; + + for (i = 0; i < nl80211->num_freqs; i++) { + while (*freqs) { + if (nl80211->freqs[i] == *freqs) + return *freqs; + freqs++; + } + } + return 0; +} + +static GByteArray * +wifi_nl80211_get_ssid (WifiData *data) +{ + WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + GByteArray *array = NULL; + struct nl80211_bss_info bss_info; + + nl80211_get_bss_info (nl80211, &bss_info); + + if (bss_info.valid) { + array = g_byte_array_sized_new (bss_info.ssid_len); + g_byte_array_append (array, (const guint8 *) bss_info.ssid, + bss_info.ssid_len); + } + + return array; +} + +static gboolean +wifi_nl80211_get_bssid (WifiData *data, struct ether_addr *out_bssid) +{ + WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + struct nl80211_bss_info bss_info; + + nl80211_get_bss_info (nl80211, &bss_info); + + if (bss_info.valid) + memcpy(out_bssid, bss_info.bssid, ETH_ALEN); + + return bss_info.valid; +} + +struct nl80211_station_info { + guint32 txrate; + gboolean txrate_valid; + guint8 signal; + gboolean signal_valid; +}; + +static int +nl80211_station_handler (struct nl_msg *msg, void *arg) +{ + struct nl80211_station_info *info = arg; + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); + struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; + struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; + static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { + [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, + [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED }, + [NL80211_STA_INFO_LLID] = { .type = NLA_U16 }, + [NL80211_STA_INFO_PLID] = { .type = NLA_U16 }, + [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 }, + }; + + static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { + [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, + [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, + [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG }, + [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, + }; + + if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), + genlmsg_attrlen (gnlh, 0), NULL) < 0) + return NL_SKIP; + + if (tb[NL80211_ATTR_STA_INFO] == NULL) + return NL_SKIP; + + if (nla_parse_nested (sinfo, NL80211_STA_INFO_MAX, + tb[NL80211_ATTR_STA_INFO], + stats_policy)) + return NL_SKIP; + + if (sinfo[NL80211_STA_INFO_TX_BITRATE] == NULL) + return NL_SKIP; + + if (nla_parse_nested (rinfo, NL80211_RATE_INFO_MAX, + sinfo[NL80211_STA_INFO_TX_BITRATE], + rate_policy)) + return NL_SKIP; + + if (rinfo[NL80211_RATE_INFO_BITRATE] == NULL) + return NL_SKIP; + + /* convert from nl80211's units of 100kbps to NM's kbps */ + info->txrate = nla_get_u16 (rinfo[NL80211_RATE_INFO_BITRATE]) * 100; + info->txrate_valid = TRUE; + + if (sinfo[NL80211_STA_INFO_SIGNAL] != NULL) { + info->signal = nl80211_xbm_to_percent ((gint8) nla_get_u8 (sinfo[NL80211_STA_INFO_SIGNAL]), 1); + info->signal_valid = TRUE; + } + + return NL_SKIP; +} + +static void +nl80211_get_ap_info (WifiDataNl80211 *nl80211, + struct nl80211_station_info *sta_info) +{ + struct nl_msg *msg; + struct nl80211_bss_info bss_info; + + memset(sta_info, 0, sizeof (*sta_info)); + + nl80211_get_bss_info (nl80211, &bss_info); + if (!bss_info.valid) + return; + + msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_STATION, 0); + if (msg) { + NLA_PUT (msg, NL80211_ATTR_MAC, ETH_ALEN, bss_info.bssid); + + nl80211_send_and_recv (nl80211, msg, nl80211_station_handler, sta_info); + if (!sta_info->signal_valid) { + /* Fall back to bss_info signal quality (both are in percent) */ + sta_info->signal = bss_info.beacon_signal; + } + } + + return; + + nla_put_failure: + nlmsg_free (msg); + return; +} + +static guint32 +wifi_nl80211_get_rate (WifiData *data) +{ + WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + struct nl80211_station_info sta_info; + + nl80211_get_ap_info (nl80211, &sta_info); + + return sta_info.txrate; +} + +static int +wifi_nl80211_get_qual (WifiData *data) +{ + WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + struct nl80211_station_info sta_info; + + nl80211_get_ap_info (nl80211, &sta_info); + return sta_info.signal; +} + +#if HAVE_NL80211_CRITICAL_PROTOCOL_CMDS +static gboolean +wifi_nl80211_indicate_addressing_running (WifiData *data, gboolean running) +{ + WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + struct nl_msg *msg; + int err; + + msg = nl80211_alloc_msg (nl80211, + running ? NL80211_CMD_CRIT_PROTOCOL_START : + NL80211_CMD_CRIT_PROTOCOL_STOP, + 0); + /* Despite the DHCP name, we're using this for any type of IP addressing, + * DHCPv4, DHCPv6, and IPv6 SLAAC. + */ + NLA_PUT_U16 (msg, NL80211_ATTR_CRIT_PROT_ID, NL80211_CRIT_PROTO_DHCP); + if (running) { + /* Give DHCP 5 seconds to complete */ + NLA_PUT_U16 (msg, NL80211_ATTR_MAX_CRIT_PROT_DURATION, 5000); + } + + err = nl80211_send_and_recv (nl80211, msg, NULL, NULL); + return err ? FALSE : TRUE; + +nla_put_failure: + nlmsg_free (msg); + return FALSE; +} +#endif + +struct nl80211_wowlan_info { + gboolean enabled; +}; + +static int +nl80211_wowlan_handler (struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); + struct nl80211_wowlan_info *info = arg; + + info->enabled = FALSE; + + if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen (gnlh, 0), NULL) < 0) + return NL_SKIP; + + if (tb[NL80211_ATTR_WOWLAN_TRIGGERS]) + info->enabled = TRUE; + + return NL_SKIP; +} + +static gboolean +wifi_nl80211_get_wowlan (WifiData *data) +{ + WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + struct nl_msg *msg; + struct nl80211_wowlan_info info; + + msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_WOWLAN, 0); + nl80211_send_and_recv (nl80211, msg, nl80211_wowlan_handler, &info); + + return info.enabled; +} + +struct nl80211_device_info { + int phy; + guint32 *freqs; + int num_freqs; + guint32 caps; + gboolean can_scan; + gboolean can_scan_ssid; + gboolean supported; + gboolean success; + gboolean can_wowlan; +}; + +#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00 +#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01 +#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02 +#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 +#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 +#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 +#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08 +#define WLAN_CIPHER_SUITE_SMS4 0x00147201 + +static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); + struct nl80211_device_info *info = arg; + struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; + struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nlattr *nl_band; + struct nlattr *nl_freq; + int rem_freq; + int rem_band; + int freq_idx; + static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { + [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, + [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, + }; + + if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen (gnlh, 0), NULL) < 0) + return NL_SKIP; + + if ( tb[NL80211_ATTR_WIPHY] == NULL + || tb[NL80211_ATTR_WIPHY_BANDS] == NULL) + return NL_SKIP; + + info->phy = nla_get_u32 (tb[NL80211_ATTR_WIPHY]); + + if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) { + info->can_scan_ssid = + nla_get_u8 (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) > 0; + } else { + /* old kernel that only had mac80211, so assume it can */ + info->can_scan_ssid = TRUE; + } + + if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) { + struct nlattr *nl_cmd; + int i; + + nla_for_each_nested (nl_cmd, tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) { + switch (nla_get_u32 (nl_cmd)) { + case NL80211_CMD_TRIGGER_SCAN: + info->can_scan = TRUE; + break; + case NL80211_CMD_CONNECT: + case NL80211_CMD_AUTHENTICATE: + /* Only devices that support CONNECT or AUTH actually support + * 802.11, unlike say ipw2x00 (up to at least kernel 3.4) which + * has minimal info support, but no actual command support. + * This check mirrors what wpa_supplicant does to determine + * whether or not to use the nl80211 driver. + */ + info->supported = TRUE; + break; + default: + break; + } + } + } + + info->num_freqs = 0; + + nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) { + if (nla_parse_nested (tb_band, NL80211_BAND_ATTR_MAX, nl_band, + NULL) < 0) + return NL_SKIP; + + nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], + rem_freq) { + nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX, + nl_freq, freq_policy); + + if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) + continue; + + info->num_freqs++; + } + } + + info->freqs = g_malloc0 (sizeof (guint32) * info->num_freqs); + + freq_idx = 0; + nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) { + if (nla_parse_nested (tb_band, NL80211_BAND_ATTR_MAX, nl_band, + NULL) < 0) + return NL_SKIP; + + nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], + rem_freq) { + nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX, + nl_freq, freq_policy); + + if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) + continue; + + info->freqs[freq_idx] = + nla_get_u32 (tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); + freq_idx++; + } + } + + if (tb[NL80211_ATTR_CIPHER_SUITES]) { + int num; + int i; + __u32 *ciphers = nla_data (tb[NL80211_ATTR_CIPHER_SUITES]); + + num = nla_len (tb[NL80211_ATTR_CIPHER_SUITES]) / sizeof (__u32); + for (i = 0; i < num; i++) { + switch (ciphers[i]) { + case WLAN_CIPHER_SUITE_WEP40: + info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP40; + break; + case WLAN_CIPHER_SUITE_WEP104: + info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP104; + break; + case WLAN_CIPHER_SUITE_TKIP: + info->caps |= (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | + NM_WIFI_DEVICE_CAP_WPA); + break; + case WLAN_CIPHER_SUITE_CCMP: + info->caps |= (NM_WIFI_DEVICE_CAP_CIPHER_CCMP | + NM_WIFI_DEVICE_CAP_RSN); + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_SMS4: + break; + default: + nm_log_dbg (LOGD_HW | LOGD_WIFI, "Don't know the meaning of NL80211_ATTR_CIPHER_SUITE %#8.8x.", ciphers[i]); + break; + } + } + } + + if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) { + struct nlattr *nl_mode; + int i; + + nla_for_each_nested (nl_mode, tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) { + if (nla_type (nl_mode) == NL80211_IFTYPE_AP) + info->caps |= NM_WIFI_DEVICE_CAP_AP; + else if (nla_type (nl_mode) == NL80211_IFTYPE_ADHOC) + info->caps |= NM_WIFI_DEVICE_CAP_ADHOC; + } + } + + if (tb[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED]) + info->can_wowlan = TRUE; + + info->success = TRUE; + + return NL_SKIP; +} + +WifiData * +wifi_nl80211_init (const char *iface, int ifindex) +{ + WifiDataNl80211 *nl80211; + struct nl_msg *msg; + struct nl80211_device_info device_info = {}; + + nl80211 = wifi_data_new (iface, ifindex, sizeof (*nl80211)); + nl80211->parent.get_mode = wifi_nl80211_get_mode; + nl80211->parent.set_mode = wifi_nl80211_set_mode; + nl80211->parent.get_freq = wifi_nl80211_get_freq; + nl80211->parent.find_freq = wifi_nl80211_find_freq; + nl80211->parent.get_ssid = wifi_nl80211_get_ssid; + nl80211->parent.get_bssid = wifi_nl80211_get_bssid; + nl80211->parent.get_rate = wifi_nl80211_get_rate; + nl80211->parent.get_qual = wifi_nl80211_get_qual; +#if HAVE_NL80211_CRITICAL_PROTOCOL_CMDS + nl80211->parent.indicate_addressing_running = wifi_nl80211_indicate_addressing_running; +#endif + nl80211->parent.deinit = wifi_nl80211_deinit; + + nl80211->nl_sock = nl_socket_alloc (); + if (nl80211->nl_sock == NULL) + goto error; + + if (genl_connect (nl80211->nl_sock)) + goto error; + + nl80211->id = genl_ctrl_resolve (nl80211->nl_sock, "nl80211"); + if (nl80211->id < 0) + goto error; + + nl80211->nl_cb = nl_cb_alloc (NL_CB_DEFAULT); + if (nl80211->nl_cb == NULL) + goto error; + + nl80211->phy = -1; + + msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_WIPHY, 0); + + if (nl80211_send_and_recv (nl80211, msg, nl80211_wiphy_info_handler, + &device_info) < 0) { + nm_log_dbg (LOGD_HW | LOGD_WIFI, + "(%s): NL80211_CMD_GET_WIPHY request failed", + nl80211->parent.iface); + goto error; + } + + if (!device_info.success) { + nm_log_dbg (LOGD_HW | LOGD_WIFI, + "(%s): NL80211_CMD_GET_WIPHY request indicated failure", + nl80211->parent.iface); + goto error; + } + + if (!device_info.supported) { + nm_log_dbg (LOGD_HW | LOGD_WIFI, + "(%s): driver does not fully support nl80211, falling back to WEXT", + nl80211->parent.iface); + goto error; + } + + if (!device_info.can_scan_ssid) { + nm_log_err (LOGD_HW | LOGD_WIFI, + "(%s): driver does not support SSID scans", + nl80211->parent.iface); + goto error; + } + + if (device_info.num_freqs == 0 || device_info.freqs == NULL) { + nm_log_err (LOGD_HW | LOGD_WIFI, + "(%s): driver reports no supported frequencies", + nl80211->parent.iface); + goto error; + } + + if (device_info.caps == 0) { + nm_log_err (LOGD_HW | LOGD_WIFI, + "(%s): driver doesn't report support of any encryption", + nl80211->parent.iface); + goto error; + } + + nl80211->phy = device_info.phy; + nl80211->freqs = device_info.freqs; + nl80211->num_freqs = device_info.num_freqs; + nl80211->parent.caps = device_info.caps; + + if (device_info.can_wowlan) + nl80211->parent.get_wowlan = wifi_nl80211_get_wowlan; + + nm_log_info (LOGD_HW | LOGD_WIFI, + "(%s): using nl80211 for WiFi device control", + nl80211->parent.iface); + + return (WifiData *) nl80211; + +error: + wifi_utils_deinit ((WifiData *) nl80211); + return NULL; +} + +gboolean +wifi_nl80211_is_wifi (const char *iface) +{ + struct nl_sock *nl_sock; + struct nl_cb *nl_cb = NULL; + struct nl_msg *msg = NULL; + int id, ifindex; + struct nl80211_iface_info iface_info = { + .mode = NM_802_11_MODE_UNKNOWN, + }; + gboolean is_wifi = FALSE; + + nl_sock = nl_socket_alloc (); + if (nl_sock == NULL) + return FALSE; + + if (genl_connect (nl_sock)) + goto error; + + ifindex = nm_platform_link_get_ifindex (iface); + if (ifindex < 0) + goto error; + + id = genl_ctrl_resolve (nl_sock, "nl80211"); + if (id < 0) + goto error; + + nl_cb = nl_cb_alloc (NL_CB_DEFAULT); + if (nl_cb) { + msg = _nl80211_alloc_msg (id, ifindex, -1, NL80211_CMD_GET_INTERFACE, 0); + if (_nl80211_send_and_recv (nl_sock, + nl_cb, + msg, + nl80211_iface_info_handler, + &iface_info) >= 0) + is_wifi = (iface_info.mode != NM_802_11_MODE_UNKNOWN); + } + + error: + if (nl_cb) + nl_cb_put (nl_cb); + nl_socket_free (nl_sock); + return is_wifi; +} + diff --git a/src/platform/wifi/wifi-utils-nl80211.h b/src/platform/wifi/wifi-utils-nl80211.h new file mode 100644 index 00000000..2a7fe874 --- /dev/null +++ b/src/platform/wifi/wifi-utils-nl80211.h @@ -0,0 +1,30 @@ +/* -*- 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 Intel Corporation. All rights reserved. + */ + +#ifndef WIFI_UTILS_NL80211_H +#define WIFI_UTILS_NL80211_H + +#include "wifi-utils.h" + +WifiData *wifi_nl80211_init (const char *iface, int ifindex); + +gboolean wifi_nl80211_is_wifi (const char *iface); + +#endif /* WIFI_UTILS_NL80211_H */ diff --git a/src/platform/wifi/wifi-utils-private.h b/src/platform/wifi/wifi-utils-private.h new file mode 100644 index 00000000..e7601752 --- /dev/null +++ b/src/platform/wifi/wifi-utils-private.h @@ -0,0 +1,77 @@ +/* -*- 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 Red Hat, Inc. + */ + +#ifndef WIFI_UTILS_PRIVATE_H +#define WIFI_UTILS_PRIVATE_H + +#include <glib.h> + +#include "NetworkManager.h" +#include "wifi-utils.h" + +struct WifiData { + char *iface; + int ifindex; + NMDeviceWifiCapabilities caps; + + NM80211Mode (*get_mode) (WifiData *data); + + gboolean (*set_mode) (WifiData *data, const NM80211Mode mode); + + /* Return current frequency in MHz (really associated BSS frequency) */ + guint32 (*get_freq) (WifiData *data); + + /* Return first supported frequency in the zero-terminated list */ + guint32 (*find_freq) (WifiData *data, const guint32 *freqs); + + /* If SSID is empty/blank (zero-length or all \0s) return NULL */ + GByteArray * (*get_ssid) (WifiData *data); + + /* Return current bitrate in Kbps */ + guint32 (*get_rate) (WifiData *data); + + gboolean (*get_bssid) (WifiData *data, struct ether_addr *out_bssid); + + /* Return a signal strength percentage 0 - 100% for the current BSSID; + * return -1 on errors or if not associated. + */ + int (*get_qual) (WifiData *data); + + void (*deinit) (WifiData *data); + + gboolean (*get_wowlan) (WifiData *data); + + /* OLPC Mesh-only functions */ + + guint32 (*get_mesh_channel) (WifiData *data); + + /* channel == 0 means "auto channel" */ + gboolean (*set_mesh_channel) (WifiData *data, guint32 channel); + + /* ssid == NULL means "auto SSID" */ + gboolean (*set_mesh_ssid) (WifiData *data, const GByteArray *ssid); + + gboolean (*indicate_addressing_running) (WifiData *data, gboolean running); +}; + +gpointer wifi_data_new (const char *iface, int ifindex, gsize len); +void wifi_data_free (WifiData *data); + +#endif /* WIFI_UTILS_PRIVATE_H */ diff --git a/src/platform/wifi/wifi-utils-wext.c b/src/platform/wifi/wifi-utils-wext.c new file mode 100644 index 00000000..cc94b69a --- /dev/null +++ b/src/platform/wifi/wifi-utils-wext.c @@ -0,0 +1,671 @@ +/* -*- 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) 2005 - 2011 Red Hat, Inc. + * Copyright (C) 2006 - 2008 Novell, Inc. + */ + +#include <config.h> +#include <errno.h> +#include <string.h> +#include <sys/ioctl.h> +#include <net/ethernet.h> +#include <unistd.h> +#include <math.h> + +#include <glib.h> + +#include "wifi-utils-private.h" +#include "wifi-utils-wext.h" +#include "nm-logging.h" +#include "nm-utils.h" + +/* Hacks necessary to #include wireless.h; yay for WEXT */ +#ifndef __user +#define __user +#endif +#include <sys/types.h> +#include <linux/types.h> +#include <sys/socket.h> +#include <linux/if.h> +#include <linux/wireless.h> + + +typedef struct { + WifiData parent; + int fd; + struct iw_quality max_qual; + gint8 num_freqs; + guint32 freqs[IW_MAX_FREQUENCIES]; +} WifiDataWext; + +/* Until a new wireless-tools comes out that has the defs and the structure, + * need to copy them here. + */ +/* Scan capability flags - in (struct iw_range *)->scan_capa */ +#define NM_IW_SCAN_CAPA_NONE 0x00 +#define NM_IW_SCAN_CAPA_ESSID 0x01 + +struct iw_range_with_scan_capa +{ + guint32 throughput; + guint32 min_nwid; + guint32 max_nwid; + guint16 old_num_channels; + guint8 old_num_frequency; + + guint8 scan_capa; + /* don't need the rest... */ +}; + +static guint32 +iw_freq_to_uint32 (struct iw_freq *freq) +{ + if (freq->e == 0) { + /* Some drivers report channel not frequency. Convert to a + * frequency; but this assumes that the device is in b/g mode. + */ + if ((freq->m >= 1) && (freq->m <= 13)) + return 2407 + (5 * freq->m); + else if (freq->m == 14) + return 2484; + } + + return (guint32) (((double) freq->m) * pow (10, freq->e) / 1000000); +} + +static void +wifi_wext_deinit (WifiData *parent) +{ + WifiDataWext *wext = (WifiDataWext *) parent; + + if (wext->fd >= 0) + close (wext->fd); +} + +static NM80211Mode +wifi_wext_get_mode (WifiData *data) +{ + WifiDataWext *wext = (WifiDataWext *) data; + struct iwreq wrq; + + memset (&wrq, 0, sizeof (struct iwreq)); + strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + + if (ioctl (wext->fd, SIOCGIWMODE, &wrq) < 0) { + if (errno != ENODEV) { + nm_log_warn (LOGD_HW | LOGD_WIFI, + "(%s): error %d getting card mode", + wext->parent.iface, errno); + } + return NM_802_11_MODE_UNKNOWN; + } + + switch (wrq.u.mode) { + case IW_MODE_ADHOC: + return NM_802_11_MODE_ADHOC; + case IW_MODE_MASTER: + return NM_802_11_MODE_AP; + case IW_MODE_INFRA: + return NM_802_11_MODE_INFRA; + default: + break; + } + return NM_802_11_MODE_UNKNOWN; +} + +static gboolean +wifi_wext_set_mode (WifiData *data, const NM80211Mode mode) +{ + WifiDataWext *wext = (WifiDataWext *) data; + struct iwreq wrq; + + if (wifi_wext_get_mode (data) == mode) + return TRUE; + + memset (&wrq, 0, sizeof (struct iwreq)); + switch (mode) { + case NM_802_11_MODE_ADHOC: + wrq.u.mode = IW_MODE_ADHOC; + break; + case NM_802_11_MODE_AP: + wrq.u.mode = IW_MODE_MASTER; + break; + case NM_802_11_MODE_INFRA: + wrq.u.mode = IW_MODE_INFRA; + break; + default: + g_warn_if_reached (); + return FALSE; + } + + strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + if (ioctl (wext->fd, SIOCSIWMODE, &wrq) < 0) { + if (errno != ENODEV) { + nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): error setting mode %d", + wext->parent.iface, mode); + } + return FALSE; + } + + return TRUE; +} + +static guint32 +wifi_wext_get_freq (WifiData *data) +{ + WifiDataWext *wext = (WifiDataWext *) data; + struct iwreq wrq; + + memset (&wrq, 0, sizeof (struct iwreq)); + strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + if (ioctl (wext->fd, SIOCGIWFREQ, &wrq) < 0) { + nm_log_warn (LOGD_HW | LOGD_WIFI, + "(%s): error getting frequency: %s", + wext->parent.iface, strerror (errno)); + return 0; + } + + return iw_freq_to_uint32 (&wrq.u.freq); +} + +static guint32 +wifi_wext_find_freq (WifiData *data, const guint32 *freqs) +{ + WifiDataWext *wext = (WifiDataWext *) data; + int i; + + for (i = 0; i < wext->num_freqs; i++) { + while (*freqs) { + if (wext->freqs[i] == *freqs) + return *freqs; + freqs++; + } + } + return 0; +} + +static GByteArray * +wifi_wext_get_ssid (WifiData *data) +{ + WifiDataWext *wext = (WifiDataWext *) data; + struct iwreq wrq; + char ssid[IW_ESSID_MAX_SIZE + 2]; + guint32 len; + GByteArray *array = NULL; + + memset (ssid, 0, sizeof (ssid)); + wrq.u.essid.pointer = (caddr_t) &ssid; + wrq.u.essid.length = sizeof (ssid); + wrq.u.essid.flags = 0; + strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + + if (ioctl (wext->fd, SIOCGIWESSID, &wrq) < 0) { + nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): couldn't get SSID: %d", + wext->parent.iface, errno); + return NULL; + } + + len = wrq.u.essid.length; + if (nm_utils_is_empty_ssid ((guint8 *) ssid, len) == FALSE) { + array = g_byte_array_sized_new (len); + g_byte_array_append (array, (const guint8 *) ssid, len); + } + + return array; +} + +static gboolean +wifi_wext_get_bssid (WifiData *data, struct ether_addr *out_bssid) +{ + WifiDataWext *wext = (WifiDataWext *) data; + struct iwreq wrq; + + memset (&wrq, 0, sizeof (wrq)); + strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + if (ioctl (wext->fd, SIOCGIWAP, &wrq) < 0) { + nm_log_warn (LOGD_HW | LOGD_WIFI, + "(%s): error getting associated BSSID: %s", + wext->parent.iface, strerror (errno)); + return FALSE; + } + memcpy (out_bssid->ether_addr_octet, &(wrq.u.ap_addr.sa_data), ETH_ALEN); + return TRUE; +} + +static guint32 +wifi_wext_get_rate (WifiData *data) +{ + WifiDataWext *wext = (WifiDataWext *) data; + struct iwreq wrq; + int err; + + memset (&wrq, 0, sizeof (wrq)); + strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + err = ioctl (wext->fd, SIOCGIWRATE, &wrq); + return ((err == 0) ? wrq.u.bitrate.value / 1000 : 0); +} + +static int +wext_qual_to_percent (const struct iw_quality *qual, + const struct iw_quality *max_qual) +{ + int percent = -1; + int level_percent = -1; + + g_return_val_if_fail (qual != NULL, -1); + g_return_val_if_fail (max_qual != NULL, -1); + + /* Magically convert the many different WEXT quality representations to a percentage */ + + nm_log_dbg (LOGD_WIFI, + "QL: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X ** MAX: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X", + (__s8) qual->qual, qual->qual, qual->qual, + (__s8) qual->level, qual->level, qual->level, + (__s8) qual->noise, qual->noise, qual->noise, + qual->updated, + (__s8) max_qual->qual, max_qual->qual, max_qual->qual, + (__s8) max_qual->level, max_qual->level, max_qual->level, + (__s8) max_qual->noise, max_qual->noise, max_qual->noise, + max_qual->updated); + + /* Try using the card's idea of the signal quality first as long as it tells us what the max quality is. + * Drivers that fill in quality values MUST treat them as percentages, ie the "Link Quality" MUST be + * bounded by 0 and max_qual->qual, and MUST change in a linear fashion. Within those bounds, drivers + * are free to use whatever they want to calculate "Link Quality". + */ + if ((max_qual->qual != 0) && !(max_qual->updated & IW_QUAL_QUAL_INVALID) && !(qual->updated & IW_QUAL_QUAL_INVALID)) + percent = (int)(100 * ((double)qual->qual / (double)max_qual->qual)); + + /* If the driver doesn't specify a complete and valid quality, we have two options: + * + * 1) dBm: driver must specify max_qual->level = 0, and have valid values for + * qual->level and (qual->noise OR max_qual->noise) + * 2) raw RSSI: driver must specify max_qual->level > 0, and have valid values for + * qual->level and max_qual->level + * + * This is the WEXT spec. If this interpretation is wrong, I'll fix it. Otherwise, + * If drivers don't conform to it, they are wrong and need to be fixed. + */ + + if ( (max_qual->level == 0) && !(max_qual->updated & IW_QUAL_LEVEL_INVALID) /* Valid max_qual->level == 0 */ + && !(qual->updated & IW_QUAL_LEVEL_INVALID) /* Must have valid qual->level */ + && ( ((max_qual->noise > 0) && !(max_qual->updated & IW_QUAL_NOISE_INVALID)) /* Must have valid max_qual->noise */ + || ((qual->noise > 0) && !(qual->updated & IW_QUAL_NOISE_INVALID))) /* OR valid qual->noise */ + ) { + /* Absolute power values (dBm) */ + + /* Reasonable fallbacks for dumb drivers that don't specify either level. */ + #define FALLBACK_NOISE_FLOOR_DBM -90 + #define FALLBACK_SIGNAL_MAX_DBM -20 + int max_level = FALLBACK_SIGNAL_MAX_DBM; + int noise = FALLBACK_NOISE_FLOOR_DBM; + int level = qual->level - 0x100; + + level = CLAMP (level, FALLBACK_NOISE_FLOOR_DBM, FALLBACK_SIGNAL_MAX_DBM); + + if ((qual->noise > 0) && !(qual->updated & IW_QUAL_NOISE_INVALID)) + noise = qual->noise - 0x100; + else if ((max_qual->noise > 0) && !(max_qual->updated & IW_QUAL_NOISE_INVALID)) + noise = max_qual->noise - 0x100; + noise = CLAMP (noise, FALLBACK_NOISE_FLOOR_DBM, FALLBACK_SIGNAL_MAX_DBM); + + /* A sort of signal-to-noise ratio calculation */ + level_percent = (int) (100 - 70 * (((double)max_level - (double)level) / + ((double)max_level - (double)noise))); + nm_log_dbg (LOGD_WIFI, "QL1: level_percent is %d. max_level %d, level %d, noise_floor %d.", + level_percent, max_level, level, noise); + } else if ( (max_qual->level != 0) + && !(max_qual->updated & IW_QUAL_LEVEL_INVALID) /* Valid max_qual->level as upper bound */ + && !(qual->updated & IW_QUAL_LEVEL_INVALID)) { + /* Relative power values (RSSI) */ + + int level = qual->level; + + /* Signal level is relavtive (0 -> max_qual->level) */ + level = CLAMP (level, 0, max_qual->level); + level_percent = (int)(100 * ((double)level / (double)max_qual->level)); + nm_log_dbg (LOGD_WIFI, "QL2: level_percent is %d. max_level %d, level %d.", + level_percent, max_qual->level, level); + } else if (percent == -1) { + nm_log_dbg (LOGD_WIFI, "QL: Could not get quality %% value from driver. Driver is probably buggy."); + } + + /* If the quality percent was 0 or doesn't exist, then try to use signal levels instead */ + if ((percent < 1) && (level_percent >= 0)) + percent = level_percent; + + nm_log_dbg (LOGD_WIFI, "QL: Final quality percent is %d (%d).", + percent, CLAMP (percent, 0, 100)); + return (CLAMP (percent, 0, 100)); +} + +static int +wifi_wext_get_qual (WifiData *data) +{ + WifiDataWext *wext = (WifiDataWext *) data; + struct iwreq wrq; + struct iw_statistics stats; + + memset (&stats, 0, sizeof (stats)); + wrq.u.data.pointer = &stats; + wrq.u.data.length = sizeof (stats); + wrq.u.data.flags = 1; /* Clear updated flag */ + strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + + if (ioctl (wext->fd, SIOCGIWSTATS, &wrq) < 0) { + nm_log_warn (LOGD_HW | LOGD_WIFI, + "(%s): error getting signal strength: %s", + wext->parent.iface, strerror (errno)); + return -1; + } + + return wext_qual_to_percent (&stats.qual, &wext->max_qual); +} + +/*********************/ +/* OLPC Mesh-only functions */ + +static guint32 +wifi_wext_get_mesh_channel (WifiData *data) +{ + WifiDataWext *wext = (WifiDataWext *) data; + guint32 freq; + int i; + + freq = wifi_utils_get_freq (data); + for (i = 0; i < wext->num_freqs; i++) { + if (freq == wext->freqs[i]) + return i + 1; + } + return 0; +} + +static gboolean +wifi_wext_set_mesh_channel (WifiData *data, guint32 channel) +{ + WifiDataWext *wext = (WifiDataWext *) data; + struct iwreq wrq; + + memset (&wrq, 0, sizeof (struct iwreq)); + strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + + if (channel > 0) { + wrq.u.freq.flags = IW_FREQ_FIXED; + wrq.u.freq.e = 0; + wrq.u.freq.m = channel; + } + + if (ioctl (wext->fd, SIOCSIWFREQ, &wrq) < 0) { + nm_log_err (LOGD_HW | LOGD_WIFI | LOGD_OLPC, + "(%s): error setting channel to %d: %s", + wext->parent.iface, channel, strerror (errno)); + return FALSE; + } + + return TRUE; +} + +static gboolean +wifi_wext_set_mesh_ssid (WifiData *data, const GByteArray *ssid) +{ + WifiDataWext *wext = (WifiDataWext *) data; + struct iwreq wrq; + guint32 len = 0; + char buf[IW_ESSID_MAX_SIZE + 1]; + + memset (buf, 0, sizeof (buf)); + if (ssid) { + len = ssid->len; + memcpy (buf, ssid->data, MIN (sizeof (buf) - 1, len)); + } + wrq.u.essid.pointer = (caddr_t) buf; + wrq.u.essid.length = len; + wrq.u.essid.flags = (len > 0) ? 1 : 0; /* 1=enable SSID, 0=disable/any */ + + strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + if (ioctl (wext->fd, SIOCSIWESSID, &wrq) == 0) + return TRUE; + + if (errno != ENODEV) { + nm_log_err (LOGD_HW | LOGD_WIFI | LOGD_OLPC, + "(%s): error setting SSID to '%s': %s", + wext->parent.iface, + ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(null)", + strerror (errno)); + } + + return FALSE; +} + +/*********************/ + +static gboolean +wext_can_scan (WifiDataWext *wext) +{ + struct iwreq wrq; + + memset (&wrq, 0, sizeof (struct iwreq)); + strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + if (ioctl (wext->fd, SIOCSIWSCAN, &wrq) < 0) { + if (errno == EOPNOTSUPP) + return FALSE; + } + return TRUE; +} + +static gboolean +wext_get_range (WifiDataWext *wext, + struct iw_range *range, + guint32 *response_len) +{ + int i = 26; + gboolean success = FALSE; + struct iwreq wrq; + + memset (&wrq, 0, sizeof (struct iwreq)); + strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + wrq.u.data.pointer = (caddr_t) range; + wrq.u.data.length = sizeof (struct iw_range); + + /* Need to give some drivers time to recover after suspend/resume + * (ex ipw3945 takes a few seconds to talk to its regulatory daemon; + * see rh bz#362421) + */ + while (i-- > 0) { + if (ioctl (wext->fd, SIOCGIWRANGE, &wrq) == 0) { + if (response_len) + *response_len = wrq.u.data.length; + success = TRUE; + break; + } else if (errno != EAGAIN) { + nm_log_err (LOGD_HW | LOGD_WIFI, + "(%s): couldn't get driver range information (%d).", + wext->parent.iface, errno); + break; + } + + g_usleep (G_USEC_PER_SEC / 4); + } + + if (i <= 0) { + nm_log_warn (LOGD_HW | LOGD_WIFI, + "(%s): driver took too long to respond to IWRANGE query.", + wext->parent.iface); + } + + return success; +} + +#define WPA_CAPS (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | \ + NM_WIFI_DEVICE_CAP_CIPHER_CCMP | \ + NM_WIFI_DEVICE_CAP_WPA | \ + NM_WIFI_DEVICE_CAP_RSN) + +static guint32 +wext_get_caps (WifiDataWext *wext, struct iw_range *range) +{ + guint32 caps = NM_WIFI_DEVICE_CAP_NONE; + + g_return_val_if_fail (wext != NULL, NM_WIFI_DEVICE_CAP_NONE); + g_return_val_if_fail (range != NULL, NM_WIFI_DEVICE_CAP_NONE); + + /* All drivers should support WEP by default */ + caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104; + + if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP) + caps |= NM_WIFI_DEVICE_CAP_CIPHER_TKIP; + + if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP) + caps |= NM_WIFI_DEVICE_CAP_CIPHER_CCMP; + + if (range->enc_capa & IW_ENC_CAPA_WPA) + caps |= NM_WIFI_DEVICE_CAP_WPA; + + if (range->enc_capa & IW_ENC_CAPA_WPA2) + caps |= NM_WIFI_DEVICE_CAP_RSN; + + /* Check for cipher support but not WPA support */ + if ( (caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP)) + && !(caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN))) { + nm_log_warn (LOGD_WIFI, "%s: device supports WPA ciphers but not WPA protocol; " + "WPA unavailable.", wext->parent.iface); + caps &= ~WPA_CAPS; + } + + /* Check for WPA support but not cipher support */ + if ( (caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN)) + && !(caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP))) { + nm_log_warn (LOGD_WIFI, "%s: device supports WPA protocol but not WPA ciphers; " + "WPA unavailable.", wext->parent.iface); + caps &= ~WPA_CAPS; + } + + /* There's no way to detect Ad-Hoc/AP mode support with WEXT + * (other than actually trying to do it), so just assume that + * Ad-Hoc is supported and AP isn't. + */ + caps |= NM_WIFI_DEVICE_CAP_ADHOC; + + return caps; +} + +WifiData * +wifi_wext_init (const char *iface, int ifindex, gboolean check_scan) +{ + WifiDataWext *wext; + struct iw_range range; + guint32 response_len = 0; + struct iw_range_with_scan_capa *scan_capa_range; + int i; + + wext = wifi_data_new (iface, ifindex, sizeof (*wext)); + wext->parent.get_mode = wifi_wext_get_mode; + wext->parent.set_mode = wifi_wext_set_mode; + wext->parent.get_freq = wifi_wext_get_freq; + wext->parent.find_freq = wifi_wext_find_freq; + wext->parent.get_ssid = wifi_wext_get_ssid; + wext->parent.get_bssid = wifi_wext_get_bssid; + wext->parent.get_rate = wifi_wext_get_rate; + wext->parent.get_qual = wifi_wext_get_qual; + wext->parent.deinit = wifi_wext_deinit; + wext->parent.get_mesh_channel = wifi_wext_get_mesh_channel; + wext->parent.set_mesh_channel = wifi_wext_set_mesh_channel; + wext->parent.set_mesh_ssid = wifi_wext_set_mesh_ssid; + + wext->fd = socket (PF_INET, SOCK_DGRAM, 0); + if (wext->fd < 0) + goto error; + + memset (&range, 0, sizeof (struct iw_range)); + if (wext_get_range (wext, &range, &response_len) == FALSE) { + nm_log_info (LOGD_HW | LOGD_WIFI, "(%s): driver WEXT range request failed", + wext->parent.iface); + goto error; + } + + if ((response_len < 300) || (range.we_version_compiled < 21)) { + nm_log_info (LOGD_HW | LOGD_WIFI, + "(%s): driver WEXT version too old (got %d, expected >= 21)", + wext->parent.iface, + range.we_version_compiled); + goto error; + } + + wext->max_qual.qual = range.max_qual.qual; + wext->max_qual.level = range.max_qual.level; + wext->max_qual.noise = range.max_qual.noise; + wext->max_qual.updated = range.max_qual.updated; + + wext->num_freqs = MIN (range.num_frequency, IW_MAX_FREQUENCIES); + for (i = 0; i < wext->num_freqs; i++) + wext->freqs[i] = iw_freq_to_uint32 (&range.freq[i]); + + /* Check for scanning capability; cards that can't scan are not supported */ + if (check_scan && (wext_can_scan (wext) == FALSE)) { + nm_log_info (LOGD_HW | LOGD_WIFI, + "(%s): drivers that cannot scan are unsupported", + wext->parent.iface); + goto error; + } + + /* Check for the ability to scan specific SSIDs. Until the scan_capa + * field gets added to wireless-tools, need to work around that by casting + * to the custom structure. + */ + scan_capa_range = (struct iw_range_with_scan_capa *) ⦥ + if (scan_capa_range->scan_capa & NM_IW_SCAN_CAPA_ESSID) { + nm_log_info (LOGD_HW | LOGD_WIFI, + "(%s): driver supports SSID scans (scan_capa 0x%02X).", + wext->parent.iface, + scan_capa_range->scan_capa); + } else { + nm_log_info (LOGD_HW | LOGD_WIFI, + "(%s): driver does not support SSID scans (scan_capa 0x%02X).", + wext->parent.iface, + scan_capa_range->scan_capa); + } + + wext->parent.caps = wext_get_caps (wext, &range); + + nm_log_info (LOGD_HW | LOGD_WIFI, + "(%s): using WEXT for WiFi device control", + wext->parent.iface); + + return (WifiData *) wext; + +error: + wifi_utils_deinit ((WifiData *) wext); + return NULL; +} + +gboolean +wifi_wext_is_wifi (const char *iface) +{ + int fd; + struct iwreq iwr; + gboolean is_wifi = FALSE; + + fd = socket (PF_INET, SOCK_DGRAM, 0); + if (fd >= 0) { + strncpy (iwr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ); + if (ioctl (fd, SIOCGIWNAME, &iwr) == 0) + is_wifi = TRUE; + close (fd); + } + return is_wifi; +} diff --git a/src/platform/wifi/wifi-utils-wext.h b/src/platform/wifi/wifi-utils-wext.h new file mode 100644 index 00000000..96ad74eb --- /dev/null +++ b/src/platform/wifi/wifi-utils-wext.h @@ -0,0 +1,30 @@ +/* -*- 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 Red Hat, Inc. + */ + +#ifndef WIFI_UTILS_WEXT_H +#define WIFI_UTILS_WEXT_H + +#include "wifi-utils.h" + +WifiData *wifi_wext_init (const char *iface, int ifindex, gboolean check_scan); + +gboolean wifi_wext_is_wifi (const char *iface); + +#endif /* WIFI_UTILS_WEXT_H */ diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c new file mode 100644 index 00000000..ff480275 --- /dev/null +++ b/src/platform/wifi/wifi-utils.c @@ -0,0 +1,225 @@ +/* -*- 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) 2005 - 2011 Red Hat, Inc. + * Copyright (C) 2006 - 2008 Novell, Inc. + */ + +#include <config.h> +#include <sys/stat.h> +#include <stdio.h> +#include <string.h> +#include <glib.h> + +#include "wifi-utils.h" +#include "wifi-utils-private.h" +#include "wifi-utils-nl80211.h" +#if HAVE_WEXT +#include "wifi-utils-wext.h" +#endif + +gpointer +wifi_data_new (const char *iface, int ifindex, gsize len) +{ + WifiData *data; + + data = g_malloc0 (len); + data->iface = g_strdup (iface); + data->ifindex = ifindex; + return data; +} + +void +wifi_data_free (WifiData *data) +{ + g_free (data->iface); + memset (data, 0, sizeof (*data)); + g_free (data); +} + +/***************************************************************/ + +WifiData * +wifi_utils_init (const char *iface, int ifindex, gboolean check_scan) +{ + WifiData *ret; + + g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (ifindex > 0, NULL); + + ret = wifi_nl80211_init (iface, ifindex); + if (ret == NULL) { +#if HAVE_WEXT + ret = wifi_wext_init (iface, ifindex, check_scan); +#endif + } + return ret; +} + +NMDeviceWifiCapabilities +wifi_utils_get_caps (WifiData *data) +{ + g_return_val_if_fail (data != NULL, NM_WIFI_DEVICE_CAP_NONE); + + return data->caps; +} + +NM80211Mode +wifi_utils_get_mode (WifiData *data) +{ + g_return_val_if_fail (data != NULL, NM_802_11_MODE_UNKNOWN); + return data->get_mode (data); +} + +gboolean +wifi_utils_set_mode (WifiData *data, const NM80211Mode mode) +{ + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail ( (mode == NM_802_11_MODE_INFRA) + || (mode == NM_802_11_MODE_AP) + || (mode == NM_802_11_MODE_ADHOC), FALSE); + + /* nl80211 probably doesn't need this */ + return data->set_mode ? data->set_mode (data, mode) : TRUE; +} + +guint32 +wifi_utils_get_freq (WifiData *data) +{ + g_return_val_if_fail (data != NULL, 0); + return data->get_freq (data); +} + +guint32 +wifi_utils_find_freq (WifiData *data, const guint32 *freqs) +{ + g_return_val_if_fail (data != NULL, 0); + g_return_val_if_fail (freqs != NULL, 0); + return data->find_freq (data, freqs); +} + +GByteArray * +wifi_utils_get_ssid (WifiData *data) +{ + g_return_val_if_fail (data != NULL, NULL); + return data->get_ssid (data); +} + +gboolean +wifi_utils_get_bssid (WifiData *data, struct ether_addr *out_bssid) +{ + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (out_bssid != NULL, FALSE); + + memset (out_bssid, 0, sizeof (*out_bssid)); + return data->get_bssid (data, out_bssid); +} + +guint32 +wifi_utils_get_rate (WifiData *data) +{ + g_return_val_if_fail (data != NULL, 0); + return data->get_rate (data); +} + +int +wifi_utils_get_qual (WifiData *data) +{ + g_return_val_if_fail (data != NULL, 0); + return data->get_qual (data); +} + +gboolean +wifi_utils_get_wowlan (WifiData *data) +{ + g_return_val_if_fail (data != NULL, 0); + if (!data->get_wowlan) + return FALSE; + return data->get_wowlan (data); +} + +void +wifi_utils_deinit (WifiData *data) +{ + g_return_if_fail (data != NULL); + data->deinit (data); + wifi_data_free (data); +} + +gboolean +wifi_utils_is_wifi (const char *iface, const char *sysfs_path) +{ + char phy80211_path[255]; + struct stat s; + + g_return_val_if_fail (iface != NULL, FALSE); + + if (sysfs_path) { + /* Check for nl80211 sysfs paths */ + g_snprintf (phy80211_path, sizeof (phy80211_path), "%s/phy80211", sysfs_path); + if ((stat (phy80211_path, &s) == 0 && (s.st_mode & S_IFDIR))) + return TRUE; + } + + if (wifi_nl80211_is_wifi (iface)) + return TRUE; + +#if HAVE_WEXT + if (wifi_wext_is_wifi (iface)) + return TRUE; +#endif + + return FALSE; +} + + +/* OLPC Mesh-only functions */ + +guint32 +wifi_utils_get_mesh_channel (WifiData *data) +{ + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (data->get_mesh_channel != NULL, FALSE); + return data->get_mesh_channel (data); +} + +gboolean +wifi_utils_set_mesh_channel (WifiData *data, guint32 channel) +{ + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (channel <= 13, FALSE); + g_return_val_if_fail (data->set_mesh_channel != NULL, FALSE); + return data->set_mesh_channel (data, channel); +} + +gboolean +wifi_utils_set_mesh_ssid (WifiData *data, const GByteArray *ssid) +{ + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (data->set_mesh_ssid != NULL, FALSE); + return data->set_mesh_ssid (data, ssid); +} + +gboolean +wifi_utils_indicate_addressing_running (WifiData *data, gboolean running) +{ + g_return_val_if_fail (data != NULL, FALSE); + if (data->indicate_addressing_running) + return data->indicate_addressing_running (data, running); + return FALSE; +} + diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h new file mode 100644 index 00000000..455e075f --- /dev/null +++ b/src/platform/wifi/wifi-utils.h @@ -0,0 +1,76 @@ +/* -*- 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) 2005 - 2011 Red Hat, Inc. + * Copyright (C) 2006 - 2008 Novell, Inc. + */ + +#ifndef WIFI_UTILS_H +#define WIFI_UTILS_H + +#include <net/ethernet.h> +#include <glib.h> + +#include "NetworkManager.h" + +typedef struct WifiData WifiData; + +gboolean wifi_utils_is_wifi (const char *iface, const char *sysfs_path); + +WifiData *wifi_utils_init (const char *iface, int ifindex, gboolean check_scan); + +void wifi_utils_deinit (WifiData *data); + +NMDeviceWifiCapabilities wifi_utils_get_caps (WifiData *data); + +NM80211Mode wifi_utils_get_mode (WifiData *data); + +gboolean wifi_utils_set_mode (WifiData *data, const NM80211Mode mode); + +/* Returns frequency in MHz */ +guint32 wifi_utils_get_freq (WifiData *data); + +/* Return the first supported frequency in the zero-terminated list */ +guint32 wifi_utils_find_freq (WifiData *data, const guint32 *freqs); + +/* Caller must free returned byte array */ +GByteArray *wifi_utils_get_ssid (WifiData *data); + +/* Caller must free returned byte array */ +gboolean wifi_utils_get_bssid (WifiData *data, struct ether_addr *out_bssid); + +/* Returns current bitrate in Kbps */ +guint32 wifi_utils_get_rate (WifiData *data); + +/* Returns quality 0 - 100% on succes, or -1 on error */ +int wifi_utils_get_qual (WifiData *data); + +/* Tells the driver DHCP or SLAAC is running */ +gboolean wifi_utils_indicate_addressing_running (WifiData *data, gboolean running); + +/* Returns true if WoWLAN is enabled on device */ +gboolean wifi_utils_get_wowlan (WifiData *data); + + +/* OLPC Mesh-only functions */ +guint32 wifi_utils_get_mesh_channel (WifiData *data); + +gboolean wifi_utils_set_mesh_channel (WifiData *data, guint32 channel); + +gboolean wifi_utils_set_mesh_ssid (WifiData *data, const GByteArray *ssid); + +#endif /* WIFI_UTILS_H */ |